diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index a387846a8..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,168 +0,0 @@ -version: 2.1 - -executors: - golang: - docker: - - image: tendermintdev/docker-tendermint-build - working_directory: /go/src/github.com/tendermint/tendermint - environment: - GOBIN: /tmp/bin - release: - machine: true - docs: - docker: - - image: tendermintdev/docker-website-deployment - environment: - AWS_REGION: us-east-1 - -commands: - run_test: - parameters: - script_path: - type: string - steps: - - attach_workspace: - at: /tmp/bin - - restore_cache: - name: "Restore source code cache" - keys: - - go-src-v1-{{ .Revision }} - - checkout - - restore_cache: - name: "Restore go modules cache" - keys: - - go-mod-v1-{{ checksum "go.sum" }} - - run: - name: "Running test" - command: | - bash << parameters.script_path >> -jobs: - setup_dependencies: - executor: golang - steps: - - checkout - - restore_cache: - name: "Restore go modules cache" - keys: - - go-mod-v1-{{ checksum "go.sum" }} - - run: - command: | - mkdir -p /tmp/bin - - run: - name: Cache go modules - command: make go-mod-cache - - run: - name: tools - command: make tools - - run: - name: "Build binaries" - command: make install install_abci - - save_cache: - name: "Save go modules cache" - key: go-mod-v1-{{ checksum "go.sum" }} - paths: - - "/go/pkg/mod" - - save_cache: - name: "Save source code cache" - key: go-src-v1-{{ .Revision }} - paths: - - ".git" - - persist_to_workspace: - root: "/tmp/bin" - paths: - - "." - - deploy_docs: - executor: docs - steps: - - checkout - - run: - name: "Pull versions" - command: git fetch origin v0.32 v0.33 - - run: - name: "Build docs" - command: make build-docs - - run: - name: "Sync to S3" - command: make sync-docs - - prepare_build: - executor: golang - steps: - - restore_cache: - name: "Restore source code cache" - keys: - - go-src-v1-{{ .Revision }} - - checkout - - run: - name: Get next release number - command: | - export LAST_TAG="`git describe --tags --abbrev=0 --match "${CIRCLE_BRANCH}.*"`" - echo "Last tag: ${LAST_TAG}" - if [ -z "${LAST_TAG}" ]; then - export LAST_TAG="${CIRCLE_BRANCH}" - echo "Last tag not found. Possibly fresh branch or feature branch. Setting ${LAST_TAG} as tag." - fi - export NEXT_TAG="`python -u scripts/release_management/bump-semver.py --version "${LAST_TAG}"`" - echo "Next tag: ${NEXT_TAG}" - echo "export CIRCLE_TAG=\"${NEXT_TAG}\"" > release-version.source - - run: - name: Build dependencies - command: make tools - - persist_to_workspace: - root: . - paths: - - "release-version.source" - - save_cache: - key: v2-release-deps-{{ checksum "go.sum" }} - paths: - - "/go/pkg/mod" - - # # Test RPC implementation against the swagger documented specs - # contract_tests: - # working_directory: /home/circleci/.go_workspace/src/github.com/tendermint/tendermint - # machine: - # image: circleci/classic:latest - # environment: - # GOBIN: /home/circleci/.go_workspace/bin - # GOPATH: /home/circleci/.go_workspace/ - # GOOS: linux - # GOARCH: amd64 - # parallelism: 1 - # steps: - # - checkout - # - run: - # name: Test RPC endpoints against swagger documentation - # command: | - # set -x - # export PATH=~/.local/bin:$PATH - # # install node and dredd - # ./scripts/get_nodejs.sh - # # build the binaries with a proper version of Go - # docker run --rm -v "$PWD":/go/src/github.com/tendermint/tendermint -w /go/src/github.com/tendermint/tendermint golang make build-linux build-contract-tests-hooks - # # This docker image works with go 1.7, we can install here the hook handler that contract-tests is going to use - # go get github.com/snikch/goodman/cmd/goodman - # make contract-tests - -workflows: - version: 2 - docs: - jobs: - - deploy_docs: - context: tendermint-docs - filters: - branches: - only: - - master - tags: - only: - - /^v.*/ - - deploy_docs: - context: tendermint-docs-staging - filters: - branches: - only: - - docs-staging - # - contract_tests: - # requires: - # - setup_dependencies diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b48354f01..77b944d40 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,4 +7,6 @@ # global owners are only requested if there isn't a more specific # codeowner specified below. For this reason, the global codeowners # are often repeated in package-level definitions. -* @ebuchman @cmwaters @tychoish @williambanfield @creachadair +* @ebuchman @tendermint/tendermint-engineering + +/spec @ebuchman @tendermint/tendermint-research @tendermint/tendermint-engineering diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index e99d57880..99455e0c4 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,13 +1,18 @@ --- -name: Bug Report +name: Bug report about: Create a report to help us squash bugs! --- **Tendermint version** (use `tendermint version` or `git rev-parse --verify HEAD` if installed from source): diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..08852d444 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Ask a question + url: https://github.com/tendermint/tendermint/discussions + about: Please ask and answer questions here diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 62c3e4f3a..77b20c09f 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,5 +1,5 @@ --- -name: Feature Request +name: Feature request about: Create a proposal to request a feature --- @@ -25,12 +25,3 @@ Are there any disadvantages of including this feature? --> ## Proposal - -____ - -#### For Admin Use - -- [ ] Not duplicate issue -- [ ] Appropriate labels applied -- [ ] Appropriate contributors tagged -- [ ] Contributor assigned/self-assigned diff --git a/.github/ISSUE_TEMPLATE/proposal.md b/.github/ISSUE_TEMPLATE/proposal.md new file mode 100644 index 000000000..d255ad765 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/proposal.md @@ -0,0 +1,28 @@ +--- +name: Protocol change proposal +about: Create a proposal to request a change to the protocol + +--- + + + +# Protocol Change Proposal + +## Summary + + + +## Problem Definition + + + +## Proposal + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 975ad1cf5..7ac4b15ca 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,32 @@ -## Description + + +--- + +#### PR checklist + +- [ ] Tests written/updated, or no tests needed +- [ ] `CHANGELOG_PENDING.md` updated, or no changelog entry needed +- [ ] Updated relevant documentation (`docs/`) and code comments, or no + documentation updates needed diff --git a/.github/auto-comment.yml b/.github/auto-comment.yml deleted file mode 100644 index 604c2f878..000000000 --- a/.github/auto-comment.yml +++ /dev/null @@ -1,16 +0,0 @@ -pullRequestOpened: | - :wave: Thanks for creating a PR! - - Before we can merge this PR, please make sure that all the following items have been - checked off. If any of the checklist items are not applicable, please leave them but - write a little note why. - - - [ ] Wrote tests - - [ ] Updated CHANGELOG_PENDING.md - - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - - [ ] Updated relevant documentation (`docs/`) and code comments - - [ ] Re-reviewed `Files changed` in the Github PR explorer - - [ ] Applied Appropriate Labels - - - Thank you for your contribution to Tendermint! :rocket: \ No newline at end of file diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 000000000..57c4bb160 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,25 @@ +coverage: + precision: 2 + round: down + range: "70...100" + status: + project: + default: + threshold: 20% + patch: off + changes: off + +github_checks: + annotations: false + +comment: false + +ignore: + - "docs" + - "DOCKER" + - "scripts" + - "**/*.pb.go" + - "libs/pubsub/query/query.peg.go" + - "*.md" + - "*.rst" + - "*.yml" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..4a6c4bb6f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,51 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + target-branch: "main" + open-pull-requests-limit: 10 + labels: + - T:dependencies + - S:automerge + + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + target-branch: "v0.34.x" + open-pull-requests-limit: 10 + labels: + - T:dependencies + - S:automerge + + - package-ecosystem: npm + directory: "/docs" + schedule: + interval: weekly + open-pull-requests-limit: 10 + + ################################### + ## + ## Update All Go Dependencies + + - package-ecosystem: gomod + directory: "/" + schedule: + interval: weekly + target-branch: "main" + open-pull-requests-limit: 10 + labels: + - T:dependencies + - S:automerge + + - package-ecosystem: gomod + directory: "/" + schedule: + interval: weekly + target-branch: "v0.34.x" + open-pull-requests-limit: 10 + labels: + - T:dependencies + - S:automerge diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 000000000..13e5ac0b5 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,6 @@ + diff --git a/.github/linters/markdownlint.yml b/.github/linters/markdownlint.yml new file mode 100644 index 000000000..40aa57733 --- /dev/null +++ b/.github/linters/markdownlint.yml @@ -0,0 +1,15 @@ +# markdownlint configuration for Super-Linter +# - https://github.com/DavidAnson/markdownlint +# - https://github.com/github/super-linter + +# Default state for all rules +default: true + +# See https://github.com/DavidAnson/markdownlint#rules--aliases for rules +MD007: {"indent": 4} +MD013: false +MD024: {siblings_only: true} +MD025: false +MD033: {no-inline-html: false} +no-hard-tabs: false +whitespace: false diff --git a/.github/linters/yaml-lint.yml b/.github/linters/yaml-lint.yml new file mode 100644 index 000000000..e6fd77d11 --- /dev/null +++ b/.github/linters/yaml-lint.yml @@ -0,0 +1,9 @@ +--- +# Default rules for YAML linting from super-linter. +# See: See https://yamllint.readthedocs.io/en/stable/rules.html +extends: default +rules: + document-end: disable + document-start: disable + line-length: disable + truthy: disable diff --git a/.github/mergify.yml b/.github/mergify.yml index 257c3f5a7..270c06fbb 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -1,13 +1,13 @@ queue_rules: - name: default conditions: - - base=v0.34.x + - base=main - label=S:automerge pull_request_rules: - - name: Automerge to v0.34.x + - name: Automerge to main conditions: - - base=v0.34.x + - base=main - label=S:automerge actions: queue: @@ -17,3 +17,11 @@ pull_request_rules: {{ title }} (#{{ number }}) {{ body }} + - name: backport patches to v0.34.x branch + conditions: + - base=main + - label=S:backport-to-v0.34.x + actions: + backport: + branches: + - v0.34.x diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..d71c82447 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,82 @@ +name: Build +# Tests runs different tests (test_abci_apps, test_abci_cli, test_apps) +# This workflow runs on every push to main or release branch and every pull requests +# All jobs will pass without running if no *{.go, .mod, .sum} files have been modified +on: + pull_request: + push: + branches: + - main + - release/** + +jobs: + build: + name: Build + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + goarch: ["arm", "amd64"] + goos: ["linux"] + timeout-minutes: 5 + steps: + - uses: actions/setup-go@v3 + with: + go-version: "1.17" + - uses: actions/checkout@v3 + - uses: technote-space/get-diff-action@v6 + with: + PATTERNS: | + **/*.go + "!test/" + go.mod + go.sum + Makefile + - name: install + run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} make build + if: "env.GIT_DIFF != ''" + + test_abci_cli: + runs-on: ubuntu-latest + needs: build + timeout-minutes: 5 + steps: + - uses: actions/setup-go@v3 + with: + go-version: "1.17" + - uses: actions/checkout@v3 + - uses: technote-space/get-diff-action@v6 + with: + PATTERNS: | + **/*.go + go.mod + go.sum + - name: install + run: make install_abci + if: "env.GIT_DIFF != ''" + - run: abci/tests/test_cli/test.sh + shell: bash + if: "env.GIT_DIFF != ''" + + test_apps: + runs-on: ubuntu-latest + needs: build + timeout-minutes: 5 + steps: + - uses: actions/setup-go@v3 + with: + go-version: "1.17" + - uses: actions/checkout@v3 + - uses: technote-space/get-diff-action@v6 + with: + PATTERNS: | + **/*.go + go.mod + go.sum + - name: install + run: make install install_abci + if: "env.GIT_DIFF != ''" + - name: test_apps + run: test/app/test.sh + shell: bash + if: "env.GIT_DIFF != ''" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml deleted file mode 100644 index bf12bc928..000000000 --- a/.github/workflows/coverage.yml +++ /dev/null @@ -1,123 +0,0 @@ -name: Test Coverage -on: - pull_request: - push: - branches: - - master - - release/** - -jobs: - split-test-files: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Create a file with all the pkgs - run: go list ./... > pkgs.txt - - name: Split pkgs into 4 files - run: split -d -n l/4 pkgs.txt pkgs.txt.part. - # cache multiple - - uses: actions/upload-artifact@v3 - with: - name: "${{ github.sha }}-00" - path: ./pkgs.txt.part.00 - - uses: actions/upload-artifact@v3 - with: - name: "${{ github.sha }}-01" - path: ./pkgs.txt.part.01 - - uses: actions/upload-artifact@v3 - with: - name: "${{ github.sha }}-02" - path: ./pkgs.txt.part.02 - - uses: actions/upload-artifact@v3 - with: - name: "${{ github.sha }}-03" - path: ./pkgs.txt.part.03 - - build-linux: - name: Build - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - goarch: ["arm", "amd64"] - timeout-minutes: 5 - steps: - - uses: actions/setup-go@v3 - with: - go-version: "^1.15.4" - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - name: install - run: GOOS=linux GOARCH=${{ matrix.goarch }} make build - if: "env.GIT_DIFF != ''" - - tests: - runs-on: ubuntu-latest - needs: split-test-files - strategy: - fail-fast: false - matrix: - part: ["00", "01", "02", "03"] - steps: - - uses: actions/setup-go@v3 - with: - go-version: "^1.15.4" - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - uses: actions/download-artifact@v3 - with: - name: "${{ github.sha }}-${{ matrix.part }}" - if: env.GIT_DIFF - - name: test & coverage report creation - run: | - cat pkgs.txt.part.${{ matrix.part }} | xargs go test -mod=readonly -timeout 8m -race -coverprofile=${{ matrix.part }}profile.out -covermode=atomic - if: env.GIT_DIFF - - uses: actions/upload-artifact@v3 - with: - name: "${{ github.sha }}-${{ matrix.part }}-coverage" - path: ./${{ matrix.part }}profile.out - - upload-coverage-report: - runs-on: ubuntu-latest - needs: tests - steps: - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - uses: actions/download-artifact@v3 - with: - name: "${{ github.sha }}-00-coverage" - if: env.GIT_DIFF - - uses: actions/download-artifact@v3 - with: - name: "${{ github.sha }}-01-coverage" - if: env.GIT_DIFF - - uses: actions/download-artifact@v3 - with: - name: "${{ github.sha }}-02-coverage" - if: env.GIT_DIFF - - uses: actions/download-artifact@v3 - with: - name: "${{ github.sha }}-03-coverage" - if: env.GIT_DIFF - - run: | - cat ./*profile.out | grep -v "mode: atomic" >> coverage.txt - if: env.GIT_DIFF - - uses: codecov/codecov-action@v3 - with: - file: ./coverage.txt - if: env.GIT_DIFF diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7610ecedd..44681245e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,14 +1,13 @@ -name: Build & Push -# Build & Push rebuilds the tendermint docker image on every push to master and creation of tags -# and pushes the image to https://hub.docker.com/r/interchainio/simapp/tags +name: Docker +# Build & Push rebuilds the Tendermint docker image on every push to main and creation of tags +# and pushes the image to https://hub.docker.com/r/tendermint/tendermint on: - pull_request: push: branches: - - master + - main tags: - - "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching v*, i.e. v1.0, v20.15.10 - - "v[0-9]+.[0-9]+.[0-9]+-rc*" # Push events to matching v*, i.e. v1.0-rc1, v20.15.10-rc5 + - "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching v*, i.e. v1.0, v20.15.10 + - "v[0-9]+.[0-9]+.[0-9]+-rc*" # Push events to matching v*, i.e. v1.0-rc1, v20.15.10-rc5 jobs: build: @@ -39,18 +38,18 @@ jobs: with: platforms: all - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + - name: Set up Docker Build + uses: docker/setup-buildx-action@v2.0.0 - name: Login to DockerHub if: ${{ github.event_name != 'pull_request' }} - uses: docker/login-action@v2 + uses: docker/login-action@v2.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Publish to Docker Hub - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v3.1.0 with: context: . file: ./DOCKER/Dockerfile diff --git a/.github/workflows/docs-deployment.yml b/.github/workflows/docs-deployment.yml new file mode 100644 index 000000000..2b8437283 --- /dev/null +++ b/.github/workflows/docs-deployment.yml @@ -0,0 +1,62 @@ +# Build and deploy the docs.tendermint.com website content. +# The static content is published to GitHub Pages. +# +# For documentation build info, see docs/DOCS_README.md. +name: Build static documentation site +on: + workflow_dispatch: # allow manual updates + push: + branches: + - main + paths: + - docs/** + - spec/** + +jobs: + # This is split into two jobs so that the build, which runs npm, does not + # have write access to anything. The deploy requires write access to publish + # to the branch used by GitHub Pages, however, so we can't just make the + # whole workflow read-only. + build: + name: VuePress build + runs-on: ubuntu-latest + container: + image: alpine:latest + permissions: + contents: read + steps: + - name: Install generator dependencies + run: | + apk add --no-cache make bash git npm + - uses: actions/checkout@v3 + with: + # We need to fetch full history so the backport branches for previous + # versions will be available for the build. + fetch-depth: 0 + - name: Build documentation + run: | + git config --global --add safe.directory "$PWD" + make build-docs + - uses: actions/upload-artifact@v3 + with: + name: build-output + path: ~/output/ + + deploy: + name: Deploy to GitHub Pages + runs-on: ubuntu-latest + needs: build + permissions: + contents: write + steps: + - uses: actions/checkout@v3 + - uses: actions/download-artifact@v3 + with: + name: build-output + path: ~/output + - name: Deploy to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: 'docs-tendermint-com' + folder: ~/output + single-commit: true diff --git a/.github/workflows/docs-toc.yml b/.github/workflows/docs-toc.yml new file mode 100644 index 000000000..99570487a --- /dev/null +++ b/.github/workflows/docs-toc.yml @@ -0,0 +1,21 @@ +# TODO(thane): Re-enable once we've pulled in the ADRs and RFCs from master. +# Verify that important design docs have ToC entries. +#name: Check documentation ToC +#on: +# pull_request: +# push: +# branches: +# - main +# +#jobs: +# check: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v3 +# - uses: technote-space/get-diff-action@v6 +# with: +# PATTERNS: | +# docs/architecture/** +# docs/rfc/** +# - run: ./docs/presubmit.sh +# if: env.GIT_DIFF diff --git a/.github/workflows/e2e-manual.yml b/.github/workflows/e2e-manual.yml index f90f88cd3..e678cd812 100644 --- a/.github/workflows/e2e-manual.yml +++ b/.github/workflows/e2e-manual.yml @@ -1,4 +1,5 @@ -# Manually run randomly generated E2E testnets (as nightly). +# Runs randomly generated E2E testnets nightly on main +# manually run e2e tests name: e2e-manual on: workflow_dispatch: @@ -28,7 +29,7 @@ jobs: - name: Generate testnets working-directory: test/e2e # When changing -g, also change the matrix groups above - run: ./build/generator -g 4 -d networks/nightly/ + run: ./build/generator -g 5 -d networks/nightly/ - name: Run ${{ matrix.p2p }} p2p testnets working-directory: test/e2e diff --git a/.github/workflows/e2e-nightly-34x.yml b/.github/workflows/e2e-nightly-34x.yml index 6a46874ef..386982c37 100644 --- a/.github/workflows/e2e-nightly-34x.yml +++ b/.github/workflows/e2e-nightly-34x.yml @@ -1,12 +1,10 @@ -# Runs randomly generated E2E testnets nightly -# on the 0.34.x release branch +# Runs randomly generated E2E testnets nightly on the 0.34.x branch. -# !! If you change something in this file, you probably want -# to update the e2e-nightly-master workflow as well! +# !! This file should be kept in sync with the e2e-nightly-main.yml file, +# modulo changes to the version labels. name: e2e-nightly-34x on: - workflow_dispatch: # allow running workflow manually, in theory schedule: - cron: '0 2 * * *' @@ -17,13 +15,13 @@ jobs: strategy: fail-fast: false matrix: - group: ['00', '01', '02', '03'] + group: ['00', '01', '02', '03', "04"] runs-on: ubuntu-latest timeout-minutes: 60 steps: - uses: actions/setup-go@v3 with: - go-version: '^1.15.4' + go-version: '1.17' - uses: actions/checkout@v3 with: @@ -37,7 +35,7 @@ jobs: - name: Generate testnets working-directory: test/e2e # When changing -g, also change the matrix groups above - run: ./build/generator -g 4 -d networks/nightly + run: ./build/generator -g 2 -d networks/nightly - name: Run testnets in group ${{ matrix.group }} working-directory: test/e2e @@ -49,7 +47,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Notify Slack on failure - uses: rtCamp/action-slack-notify@f565a63638bd3615e76249bffab00fcb9dab90f7 + uses: rtCamp/action-slack-notify@12e36fc18b0689399306c2e0b3e0f2978b7f1ee7 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: tendermint-internal @@ -58,19 +56,3 @@ jobs: SLACK_COLOR: danger SLACK_MESSAGE: Nightly E2E tests failed on v0.34.x SLACK_FOOTER: '' - - e2e-nightly-success: # may turn this off once they seem to pass consistently - needs: e2e-nightly-test - if: ${{ success() }} - runs-on: ubuntu-latest - steps: - - name: Notify Slack on success - uses: rtCamp/action-slack-notify@f565a63638bd3615e76249bffab00fcb9dab90f7 - env: - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - SLACK_CHANNEL: tendermint-internal - SLACK_USERNAME: Nightly E2E Tests - SLACK_ICON_EMOJI: ':white_check_mark:' - SLACK_COLOR: good - SLACK_MESSAGE: Nightly E2E tests passed on v0.34.x - SLACK_FOOTER: '' diff --git a/.github/workflows/e2e-nightly-master.yml b/.github/workflows/e2e-nightly-main.yml similarity index 60% rename from .github/workflows/e2e-nightly-master.yml rename to .github/workflows/e2e-nightly-main.yml index 70ddb5534..467909981 100644 --- a/.github/workflows/e2e-nightly-master.yml +++ b/.github/workflows/e2e-nightly-main.yml @@ -1,73 +1,73 @@ -# Runs randomly generated E2E testnets nightly on master +# Runs randomly generated E2E testnets nightly on main -# !! If you change something in this file, you probably want -# to update the e2e-nightly-34x workflow as well! +# !! Relevant changes to this file should be propagated to the e2e-nightly-x +# files for the supported backport branches, when appropriate, modulo version +# markers. -name: e2e-nightly-master +name: e2e-nightly-main on: - workflow_dispatch: # allow running workflow manually schedule: - cron: '0 2 * * *' jobs: - e2e-nightly-test-2: + e2e-nightly-test: # Run parallel jobs for the listed testnet groups (must match the # ./build/generator -g flag) strategy: fail-fast: false matrix: - group: ['00', '01', '02', '03'] + group: ['00', '01', '02', '03', "04"] runs-on: ubuntu-latest timeout-minutes: 60 steps: - uses: actions/setup-go@v3 with: - go-version: '1.15' + go-version: '1.17' - uses: actions/checkout@v3 - name: Build working-directory: test/e2e # Run make jobs in parallel, since we can't run steps in parallel. - run: make -j2 docker generator runner + run: make -j2 docker generator runner tests - name: Generate testnets working-directory: test/e2e # When changing -g, also change the matrix groups above - run: ./build/generator -g 4 -d networks/nightly + run: ./build/generator -g 5 -d networks/nightly/ - - name: Run testnets in group ${{ matrix.group }} + - name: Run ${{ matrix.p2p }} p2p testnets working-directory: test/e2e run: ./run-multiple.sh networks/nightly/*-group${{ matrix.group }}-*.toml - e2e-nightly-fail-2: - needs: e2e-nightly-test-2 + e2e-nightly-fail: + needs: e2e-nightly-test if: ${{ failure() }} runs-on: ubuntu-latest steps: - name: Notify Slack on failure - uses: rtCamp/action-slack-notify@f565a63638bd3615e76249bffab00fcb9dab90f7 + uses: rtCamp/action-slack-notify@12e36fc18b0689399306c2e0b3e0f2978b7f1ee7 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: tendermint-internal SLACK_USERNAME: Nightly E2E Tests SLACK_ICON_EMOJI: ':skull:' SLACK_COLOR: danger - SLACK_MESSAGE: Nightly E2E tests failed on master + SLACK_MESSAGE: Nightly E2E tests failed on main SLACK_FOOTER: '' - e2e-nightly-success: # may turn this off once they seem to pass consistently - needs: e2e-nightly-test-2 + e2e-nightly-success: # may turn this off once they seem to pass consistently + needs: e2e-nightly-test if: ${{ success() }} runs-on: ubuntu-latest steps: - name: Notify Slack on success - uses: rtCamp/action-slack-notify@f565a63638bd3615e76249bffab00fcb9dab90f7 + uses: rtCamp/action-slack-notify@12e36fc18b0689399306c2e0b3e0f2978b7f1ee7 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: tendermint-internal SLACK_USERNAME: Nightly E2E Tests SLACK_ICON_EMOJI: ':white_check_mark:' SLACK_COLOR: good - SLACK_MESSAGE: Nightly E2E tests passed on master + SLACK_MESSAGE: Nightly E2E tests passed on main SLACK_FOOTER: '' diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 91f1fd14f..a84c701d6 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -1,11 +1,12 @@ name: e2e -# Runs the CI end-to-end test network on all pushes to master or release branches +# Runs the CI end-to-end test network on all pushes to main or release branches # and every pull request, but only if any Go files have been changed. on: + workflow_dispatch: # allow running workflow manually pull_request: push: branches: - - master + - main - release/** jobs: @@ -15,7 +16,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: '^1.15.4' + go-version: '1.17' - uses: actions/checkout@v3 - uses: technote-space/get-diff-action@v6 with: @@ -27,15 +28,10 @@ jobs: - name: Build working-directory: test/e2e # Run two make jobs in parallel, since we can't run steps in parallel. - run: make -j2 docker runner + run: make -j2 docker runner tests if: "env.GIT_DIFF != ''" - name: Run CI testnet working-directory: test/e2e - run: ./build/runner -f networks/ci.toml + run: ./run-multiple.sh networks/ci.toml if: "env.GIT_DIFF != ''" - - - name: Emit logs on failure - if: ${{ failure() }} - working-directory: test/e2e - run: ./build/runner -f networks/ci.toml logs diff --git a/.github/workflows/fuzz-nightly.yml b/.github/workflows/fuzz-nightly.yml index 1208b45cd..49df2dd41 100644 --- a/.github/workflows/fuzz-nightly.yml +++ b/.github/workflows/fuzz-nightly.yml @@ -1,9 +1,13 @@ # Runs fuzzing nightly. -name: fuzz-nightly +name: Fuzz Tests on: - workflow_dispatch: # allow running workflow manually + workflow_dispatch: # allow running workflow manually schedule: - cron: '0 3 * * *' + pull_request: + branches: [main] + paths: + - "test/fuzz/**/*.go" jobs: fuzz-nightly-test: @@ -11,13 +15,13 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: '1.15' + go-version: '1.17' - uses: actions/checkout@v3 - name: Install go-fuzz working-directory: test/fuzz - run: go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build + run: go install github.com/dvyukov/go-fuzz/go-fuzz@latest github.com/dvyukov/go-fuzz/go-fuzz-build@latest - name: Fuzz mempool working-directory: test/fuzz @@ -49,14 +53,14 @@ jobs: with: name: crashers path: test/fuzz/**/crashers - retention-days: 1 + retention-days: 3 - name: Archive suppressions uses: actions/upload-artifact@v3 with: name: suppressions path: test/fuzz/**/suppressions - retention-days: 1 + retention-days: 3 - name: Set crashers count working-directory: test/fuzz @@ -72,7 +76,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Notify Slack if any crashers - uses: rtCamp/action-slack-notify@f565a63638bd3615e76249bffab00fcb9dab90f7 + uses: rtCamp/action-slack-notify@12e36fc18b0689399306c2e0b3e0f2978b7f1ee7 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: tendermint-internal diff --git a/.github/workflows/janitor.yml b/.github/workflows/janitor.yml new file mode 100644 index 000000000..ceb21941d --- /dev/null +++ b/.github/workflows/janitor.yml @@ -0,0 +1,16 @@ +name: Janitor +# Janitor cleans up previous runs of various workflows +# To add more workflows to cancel visit https://api.github.com/repos/tendermint/tendermint/actions/workflows and find the actions name +on: + pull_request: + +jobs: + cancel: + name: "Cancel Previous Runs" + runs-on: ubuntu-latest + timeout-minutes: 3 + steps: + - uses: styfle/cancel-workflow-action@0.10.0 + with: + workflow_id: 1041851,1401230,2837803 + access_token: ${{ github.token }} diff --git a/.github/workflows/linkchecker.yml b/.github/workflows/linkchecker.yml deleted file mode 100644 index e2ba80861..000000000 --- a/.github/workflows/linkchecker.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Check Markdown links -on: - schedule: - - cron: '* */24 * * *' -jobs: - markdown-link-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: creachadair/github-action-markdown-link-check@master - with: - folder-path: "docs" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c0eb3ca4d..be1dde8b8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,12 +1,18 @@ -name: Lint -# Lint runs golangci-lint over the entire Tendermint repository -# This workflow is run on every pull request and push to master -# The `golangci` job will pass without running if no *.{go, mod, sum} files have been modified. +name: Golang Linter +# Lint runs golangci-lint over the entire Tendermint repository. +# +# This workflow is run on every pull request and push to main. +# +# The `golangci` job will pass without running if no *.{go, mod, sum} +# files have been modified. +# +# To run this locally, simply run `make lint` from the root of the repo. + on: pull_request: push: branches: - - master + - main jobs: golangci: name: golangci-lint @@ -16,7 +22,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: '^1.16' + go-version: '1.17' - uses: technote-space/get-diff-action@v6 with: PATTERNS: | @@ -25,7 +31,9 @@ jobs: go.sum - uses: golangci/golangci-lint-action@v3 with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. + # Required: the version of golangci-lint is required and + # must be specified without patch version: we always use the + # latest patch version. version: v1.45 args: --timeout 10m github-token: ${{ secrets.github_token }} diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index be0f103b1..0caa6c679 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,14 +1,14 @@ -name: Lint +name: Markdown Linter on: push: branches: - - master + - main paths: - "**.md" - "**.yml" - "**.yaml" pull_request: - branches: [master] + branches: [main] paths: - "**.md" - "**.yml" @@ -21,12 +21,12 @@ jobs: - name: Checkout Code uses: actions/checkout@v3 - name: Lint Code Base - uses: docker://github/super-linter:v3 + uses: docker://github/super-linter:v4 env: - LINTER_RULES_PATH: . VALIDATE_ALL_CODEBASE: true - DEFAULT_BRANCH: master + DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VALIDATE_MD: true VALIDATE_OPENAPI: true VALIDATE_YAML: true + YAML_CONFIG_FILE: yaml-lint.yml diff --git a/.github/workflows/markdown-links.yml b/.github/workflows/markdown-links.yml new file mode 100644 index 000000000..6aef1baf8 --- /dev/null +++ b/.github/workflows/markdown-links.yml @@ -0,0 +1,23 @@ +name: Check Markdown links + +on: + push: + branches: + - main + pull_request: + branches: [main] + +jobs: + markdown-link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: technote-space/get-diff-action@v6 + with: + PATTERNS: | + **/**.md + - uses: creachadair/github-action-markdown-link-check@master + with: + check-modified-files-only: 'yes' + config-file: '.md-link-check.json' + if: env.GIT_DIFF diff --git a/.github/workflows/proto-lint.yml b/.github/workflows/proto-lint.yml index f7b6541cd..6e078c6f7 100644 --- a/.github/workflows/proto-lint.yml +++ b/.github/workflows/proto-lint.yml @@ -5,7 +5,7 @@ on: - 'proto/**' push: branches: - - v0.34.x + - main paths: - 'proto/**' diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml deleted file mode 100644 index 6eec3f46f..000000000 --- a/.github/workflows/proto.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Protobuf -# Protobuf runs buf (https://buf.build/) lint and check-breakage -# This workflow is only run when a .proto file has been modified -on: - pull_request: - paths: - - "**.proto" -jobs: - proto-lint: - runs-on: ubuntu-latest - timeout-minutes: 4 - steps: - - uses: actions/checkout@v3 - - name: lint - run: make proto-lint - proto-breakage: - runs-on: ubuntu-latest - timeout-minutes: 4 - steps: - - uses: actions/checkout@v3 - - name: check-breakage - run: make proto-check-breaking-ci diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5bf5441ab..4197d0243 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: "Release" on: push: tags: - - "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching v*, i.e. v1.0, v20.15.10 + - "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching v*, i.e. v1.0, v20.15.10 jobs: goreleaser: @@ -16,12 +16,20 @@ jobs: - uses: actions/setup-go@v3 with: - go-version: '^1.15.4' + go-version: '1.17' - - run: echo https://github.com/tendermint/tendermint/blob/${GITHUB_REF#refs/tags/}/CHANGELOG.md#${GITHUB_REF#refs/tags/} > ../release_notes.md - - - name: Run GoReleaser + - name: Build uses: goreleaser/goreleaser-action@v3 + if: ${{ github.event_name == 'pull_request' }} + with: + version: latest + args: build --skip-validate # skip validate skips initial sanity checks in order to be able to fully run + + - run: echo https://github.com/tendermint/tendermint/blob/${GITHUB_REF#refs/tags/}/CHANGELOG.md#${GITHUB_REF#refs/tags/} > ../release_notes.md + + - name: Release + uses: goreleaser/goreleaser-action@v3 + if: startsWith(github.ref, 'refs/tags/') with: version: latest args: release --rm-dist --release-notes=../release_notes.md diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6a03003cc..4089abfbc 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,6 +13,8 @@ jobs: stale-pr-message: "This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions." - days-before-stale: 10 - days-before-close: 4 + days-before-stale: -1 + days-before-close: -1 + days-before-pr-stale: 10 + days-before-pr-close: 4 exempt-pr-labels: "S:wip" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 67f63538c..1904c37ed 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,146 +1,34 @@ -name: Tests -# Tests runs different tests (test_abci_apps, test_abci_cli, test_apps) -# This workflow runs on every push to master or release branch and every pull requests -# All jobs will pass without running if no *{.go, .mod, .sum} files have been modified +name: Test on: pull_request: push: + paths: + - "**.go" branches: - - master + - main - release/** jobs: - cleanup-runs: + tests: runs-on: ubuntu-latest - steps: - - uses: rokroskar/workflow-run-cleanup-action@master - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'" - - build: - name: Build - runs-on: ubuntu-latest - timeout-minutes: 5 + strategy: + fail-fast: false + matrix: + part: ["00", "01", "02", "03", "04", "05"] steps: - uses: actions/setup-go@v3 with: - go-version: "^1.15.4" + go-version: "1.17" - uses: actions/checkout@v3 - uses: technote-space/get-diff-action@v6 with: PATTERNS: | **/**.go + "!test/" go.mod go.sum - - name: install - run: make install install_abci - if: "env.GIT_DIFF != ''" - - uses: actions/cache@v3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - if: env.GIT_DIFF - # Cache binaries for use by other jobs - - uses: actions/cache@v3 - with: - path: ~/go/bin - key: ${{ runner.os }}-${{ github.sha }}-tm-binary - if: env.GIT_DIFF - - test_abci_apps: - runs-on: ubuntu-latest - needs: build - timeout-minutes: 5 - steps: - - uses: actions/setup-go@v3 - with: - go-version: "^1.15.4" - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - uses: actions/cache@v3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - if: env.GIT_DIFF - - uses: actions/cache@v3 - with: - path: ~/go/bin - key: ${{ runner.os }}-${{ github.sha }}-tm-binary - if: env.GIT_DIFF - - name: test_abci_apps - run: abci/tests/test_app/test.sh - shell: bash - if: env.GIT_DIFF - - test_abci_cli: - runs-on: ubuntu-latest - needs: build - timeout-minutes: 5 - steps: - - uses: actions/setup-go@v3 - with: - go-version: "^1.15.4" - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - uses: actions/cache@v3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - if: env.GIT_DIFF - - uses: actions/cache@v3 - with: - path: ~/go/bin - key: ${{ runner.os }}-${{ github.sha }}-tm-binary - if: env.GIT_DIFF - - run: abci/tests/test_cli/test.sh - shell: bash - if: env.GIT_DIFF - - test_apps: - runs-on: ubuntu-latest - needs: build - timeout-minutes: 5 - steps: - - uses: actions/setup-go@v3 - with: - go-version: "^1.15.4" - - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6 - with: - PATTERNS: | - **/**.go - go.mod - go.sum - - uses: actions/cache@v3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - if: env.GIT_DIFF - - uses: actions/cache@v3 - with: - path: ~/go/bin - key: ${{ runner.os }}-${{ github.sha }}-tm-binary - if: env.GIT_DIFF - - name: test_apps - run: test/app/test.sh - shell: bash + Makefile + - name: Run Go Tests + run: | + make test-group-${{ matrix.part }} NUM_SPLIT=6 if: env.GIT_DIFF diff --git a/.gitignore b/.gitignore index 1986b10c8..29dec09b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,58 +1,56 @@ -*.swp -*.swo -.bak *.bak +*.iml +*.swo +*.swp +*/.glide +*/vendor .DS_Store -build/* -rpc/test/.tendermint -.tendermint -remote_dump +.bak +.idea/ .revision -vendor +.tendermint +.tendermint-lite +.terraform .vagrant -test/e2e/build -test/maverick/maverick -test/e2e/networks/*/ -test/p2p/data/ -test/logs +.vendor-new/ +.vscode/ +abci/abci-cli +addrbook.json +artifacts/* +build/* coverage.txt +docs/.vuepress/dist docs/_build docs/dist -docs/.vuepress/dist -*.log -abci-cli docs/node_modules/ +docs/spec +docs/.vuepress/public/rpc index.html.md - -scripts/wal2json/wal2json -scripts/cutWALUntil/cutWALUntil - -.idea/ -*.iml - -.vscode/ - libs/pubsub/query/fuzz_test/output +profile\.out +remote_dump +rpc/test/.tendermint +scripts/cutWALUntil/cutWALUntil +scripts/wal2json/wal2json shunit2 - -.tendermint-lite -addrbook.json - -*/vendor -.vendor-new/ -*/.glide -.terraform terraform.tfstate terraform.tfstate.backup terraform.tfstate.d -profile\.out +test/app/grpc_client test/e2e/build test/e2e/networks/*/ test/logs -test/maverick/maverick test/p2p/data/ vendor test/fuzz/**/corpus test/fuzz/**/crashers test/fuzz/**/suppressions test/fuzz/**/*.zip +proto/spec/**/*.pb.go +*.aux +*.bbl +*.blg +*.log +*.pdf +*.gz +*.dvi diff --git a/.golangci.yml b/.golangci.yml index 9d846393d..46aa61d6c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -8,14 +8,7 @@ linters: - dupl - errcheck - exportloopref - # - funlen - # - gochecknoglobals - # - gochecknoinits - # - gocognit - goconst - # - gocritic - # - gocyclo - # - godox - gofmt - goimports - revive @@ -23,48 +16,31 @@ linters: - gosimple - govet - ineffassign - # - interfacer - - lll - # - maligned - # - misspell + - misspell - nakedret - nolintlint - prealloc - staticcheck - structcheck - stylecheck - # - typecheck + - typecheck - unconvert - # - unparam - unused - varcheck - # - whitespace - # - wsl issues: exclude-rules: - path: _test\.go linters: - gosec - - linters: - - lll - source: "https://" max-same-issues: 50 linters-settings: dogsled: max-blank-identifiers: 3 - maligned: - suggest-new: true - # govet: - # check-shadowing: true - revive: + golint: min-confidence: 0 maligned: suggest-new: true misspell: locale: US - ignore-words: - - behaviour - - diff --git a/.goreleaser.yml b/.goreleaser.yml index 339abb8aa..28c6a017d 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -5,7 +5,7 @@ env: - GO111MODULE=on builds: - - id: "Tendermint" + - id: "tendermint" main: ./cmd/tendermint/main.go ldflags: - -s -w -X github.com/tendermint/tendermint/version.TMCoreSemVer={{ .Version }} @@ -26,3 +26,11 @@ checksum: release: name_template: "{{.Version}} (WARNING: BETA SOFTWARE)" + +archives: + - files: + - LICENSE + - README.md + - UPGRADING.md + - SECURITY.md + - CHANGELOG.md diff --git a/.markdownlint.yml b/.markdownlint.yml index 1637001cc..3d950fbb8 100644 --- a/.markdownlint.yml +++ b/.markdownlint.yml @@ -1,5 +1,12 @@ -default: true, -MD007: { "indent": 4 } +# markdownlint configuration +# https://github.com/DavidAnson/markdownlint + +# Default state for all rules +default: true + +# See https://github.com/DavidAnson/markdownlint#rules--aliases for rules +MD001: false +MD007: {indent: 4} MD013: false MD024: { siblings_only: true } MD025: false diff --git a/.md-link-check.json b/.md-link-check.json new file mode 100644 index 000000000..6f47fa2c9 --- /dev/null +++ b/.md-link-check.json @@ -0,0 +1,6 @@ +{ + "retryOn429": true, + "retryCount": 5, + "fallbackRetryDelay": "30s", + "aliveStatusCodes": [200, 206, 503] +} diff --git a/.mergify.yml b/.mergify.yml deleted file mode 100644 index b1bef433d..000000000 --- a/.mergify.yml +++ /dev/null @@ -1,10 +0,0 @@ -pull_request_rules: - - name: Automerge to master - conditions: - - base=master - - label=S:automerge - actions: - merge: - method: squash - strict: true - commit_message: title+body diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 3a42e525f..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "protoc": { - "options": [ - "--proto_path=${workspaceRoot}/proto", - "--proto_path=${workspaceRoot}/third_party/proto" - ] - } -} diff --git a/Makefile b/Makefile index b0c3b87a6..a44aa6b3c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ PACKAGES=$(shell go list ./...) -OUTPUT?=build/tendermint +BUILDDIR?=$(CURDIR)/build +OUTPUT?=$(BUILDDIR)/tendermint BUILD_TAGS?=tendermint @@ -286,3 +287,25 @@ endif contract-tests: dredd .PHONY: contract-tests + +# Implements test splitting and running. This is pulled directly from +# the github action workflows for better local reproducibility. + +GO_TEST_FILES != find $(CURDIR) -name "*_test.go" + +# default to four splits by default +NUM_SPLIT ?= 4 + +$(BUILDDIR): + mkdir -p $@ + +# The format statement filters out all packages that don't have tests. +# Note we need to check for both in-package tests (.TestGoFiles) and +# out-of-package tests (.XTestGoFiles). +$(BUILDDIR)/packages.txt:$(GO_TEST_FILES) $(BUILDDIR) + go list -f "{{ if (or .TestGoFiles .XTestGoFiles) }}{{ .ImportPath }}{{ end }}" ./... | sort > $@ + +split-test-packages:$(BUILDDIR)/packages.txt + split -d -n l/$(NUM_SPLIT) $< $<. +test-group-%:split-test-packages + cat $(BUILDDIR)/packages.txt.$* | xargs go test -mod=readonly -timeout=5m -race -coverprofile=$(BUILDDIR)/$*.profile.out diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index 29c000189..8f28e2852 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -171,12 +171,6 @@ func (app *Application) Query(reqQuery types.RequestQuery) (resQuery types.Respo return resQuery } -func (app *Application) PrepareProposal( - req types.RequestPrepareProposal) types.ResponsePrepareProposal { - return types.ResponsePrepareProposal{ - BlockData: req.BlockData} -} - func (app *Application) ProcessProposal( req types.RequestProcessProposal) types.ResponseProcessProposal { for _, tx := range req.Txs { diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index b93e5d9e4..b24c0d268 100644 --- a/abci/example/kvstore/persistent_kvstore.go +++ b/abci/example/kvstore/persistent_kvstore.go @@ -76,6 +76,10 @@ func (app *PersistentKVStoreApplication) DeliverTx(req types.RequestDeliverTx) t return app.execValidatorTx(req.Tx) } + if isPrepareTx(req.Tx) { + return app.execPrepareTx(req.Tx) + } + // otherwise, update the key-value store return app.app.DeliverTx(req) } @@ -172,11 +176,7 @@ func (app *PersistentKVStoreApplication) ApplySnapshotChunk( func (app *PersistentKVStoreApplication) PrepareProposal( req types.RequestPrepareProposal) types.ResponsePrepareProposal { - if len(req.BlockData) > 1 && false { // this breaks TC: TestReactorValidatorSetChanges - req.BlockData[1] = []byte("modified tx") - } - - return types.ResponsePrepareProposal{BlockData: req.BlockData} + return types.ResponsePrepareProposal{TxRecords: app.substPrepareTx(req.Txs, req.MaxTxBytes)} } func (app *PersistentKVStoreApplication) ProcessProposal( @@ -303,3 +303,50 @@ func (app *PersistentKVStoreApplication) updateValidator(v types.ValidatorUpdate return types.ResponseDeliverTx{Code: code.CodeTypeOK} } + +// ----------------------------- + +const PreparePrefix = "prepare" + +func isPrepareTx(tx []byte) bool { + return bytes.HasPrefix(tx, []byte(PreparePrefix)) +} + +// execPrepareTx is noop. tx data is considered as placeholder +// and is substitute at the PrepareProposal. +func (app *PersistentKVStoreApplication) execPrepareTx(tx []byte) types.ResponseDeliverTx { + // noop + return types.ResponseDeliverTx{} +} + +// substPrepareTx substitutes all the transactions prefixed with 'prepare' in the +// proposal for transactions with the prefix stripped. +// It marks all of the original transactions as 'REMOVED' so that +// Tendermint will remove them from its mempool. +func (app *PersistentKVStoreApplication) substPrepareTx(blockData [][]byte, maxTxBytes int64) []*types.TxRecord { + trs := make([]*types.TxRecord, 0, len(blockData)) + var removed []*types.TxRecord + var totalBytes int64 + for _, tx := range blockData { + txMod := tx + action := types.TxRecord_UNMODIFIED + if isPrepareTx(tx) { + removed = append(removed, &types.TxRecord{ + Tx: tx, + Action: types.TxRecord_REMOVED, + }) + txMod = bytes.TrimPrefix(tx, []byte(PreparePrefix)) + action = types.TxRecord_ADDED + } + totalBytes += int64(len(txMod)) + if totalBytes > maxTxBytes { + break + } + trs = append(trs, &types.TxRecord{ + Tx: txMod, + Action: action, + }) + } + + return append(trs, removed...) +} diff --git a/abci/types/application.go b/abci/types/application.go index 78a8df474..31d6b9b3b 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -22,11 +22,12 @@ type Application interface { // Consensus Connection InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain w validators/other info from TendermintCore PrepareProposal(RequestPrepareProposal) ResponsePrepareProposal + ProcessProposal(RequestProcessProposal) ResponseProcessProposal BeginBlock(RequestBeginBlock) ResponseBeginBlock // Signals the beginning of a block DeliverTx(RequestDeliverTx) ResponseDeliverTx // Deliver a tx for full processing EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set Commit() ResponseCommit // Commit the state and return the application Merkle root hash - ProcessProposal(RequestProcessProposal) ResponseProcessProposal + // State Sync Connection ListSnapshots(RequestListSnapshots) ResponseListSnapshots // List available snapshots @@ -100,9 +101,19 @@ func (BaseApplication) ApplySnapshotChunk(req RequestApplySnapshotChunk) Respons } func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepareProposal { - return ResponsePrepareProposal{ - BlockData: req.BlockData, + trs := make([]*TxRecord, 0, len(req.Txs)) + var totalBytes int64 + for _, tx := range req.Txs { + totalBytes += int64(len(tx)) + if totalBytes > req.MaxTxBytes { + break + } + trs = append(trs, &TxRecord{ + Action: TxRecord_UNMODIFIED, + Tx: tx, + }) } + return ResponsePrepareProposal{TxRecords: trs} } func (BaseApplication) ProcessProposal(req RequestProcessProposal) ResponseProcessProposal { diff --git a/abci/types/mocks/application.go b/abci/types/mocks/application.go new file mode 100644 index 000000000..d945bf5f3 --- /dev/null +++ b/abci/types/mocks/application.go @@ -0,0 +1,224 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + types "github.com/tendermint/tendermint/abci/types" +) + +// Application is an autogenerated mock type for the Application type +type Application struct { + mock.Mock +} + +// ApplySnapshotChunk provides a mock function with given fields: _a0 +func (_m *Application) ApplySnapshotChunk(_a0 types.RequestApplySnapshotChunk) types.ResponseApplySnapshotChunk { + ret := _m.Called(_a0) + + var r0 types.ResponseApplySnapshotChunk + if rf, ok := ret.Get(0).(func(types.RequestApplySnapshotChunk) types.ResponseApplySnapshotChunk); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseApplySnapshotChunk) + } + + return r0 +} + +// BeginBlock provides a mock function with given fields: _a0 +func (_m *Application) BeginBlock(_a0 types.RequestBeginBlock) types.ResponseBeginBlock { + ret := _m.Called(_a0) + + var r0 types.ResponseBeginBlock + if rf, ok := ret.Get(0).(func(types.RequestBeginBlock) types.ResponseBeginBlock); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseBeginBlock) + } + + return r0 +} + +// CheckTx provides a mock function with given fields: _a0 +func (_m *Application) CheckTx(_a0 types.RequestCheckTx) types.ResponseCheckTx { + ret := _m.Called(_a0) + + var r0 types.ResponseCheckTx + if rf, ok := ret.Get(0).(func(types.RequestCheckTx) types.ResponseCheckTx); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseCheckTx) + } + + return r0 +} + +// Commit provides a mock function with given fields: +func (_m *Application) Commit() types.ResponseCommit { + ret := _m.Called() + + var r0 types.ResponseCommit + if rf, ok := ret.Get(0).(func() types.ResponseCommit); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(types.ResponseCommit) + } + + return r0 +} + +// DeliverTx provides a mock function with given fields: _a0 +func (_m *Application) DeliverTx(_a0 types.RequestDeliverTx) types.ResponseDeliverTx { + ret := _m.Called(_a0) + + var r0 types.ResponseDeliverTx + if rf, ok := ret.Get(0).(func(types.RequestDeliverTx) types.ResponseDeliverTx); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseDeliverTx) + } + + return r0 +} + +// EndBlock provides a mock function with given fields: _a0 +func (_m *Application) EndBlock(_a0 types.RequestEndBlock) types.ResponseEndBlock { + ret := _m.Called(_a0) + + var r0 types.ResponseEndBlock + if rf, ok := ret.Get(0).(func(types.RequestEndBlock) types.ResponseEndBlock); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseEndBlock) + } + + return r0 +} + +// Info provides a mock function with given fields: _a0 +func (_m *Application) Info(_a0 types.RequestInfo) types.ResponseInfo { + ret := _m.Called(_a0) + + var r0 types.ResponseInfo + if rf, ok := ret.Get(0).(func(types.RequestInfo) types.ResponseInfo); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseInfo) + } + + return r0 +} + +// InitChain provides a mock function with given fields: _a0 +func (_m *Application) InitChain(_a0 types.RequestInitChain) types.ResponseInitChain { + ret := _m.Called(_a0) + + var r0 types.ResponseInitChain + if rf, ok := ret.Get(0).(func(types.RequestInitChain) types.ResponseInitChain); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseInitChain) + } + + return r0 +} + +// ListSnapshots provides a mock function with given fields: _a0 +func (_m *Application) ListSnapshots(_a0 types.RequestListSnapshots) types.ResponseListSnapshots { + ret := _m.Called(_a0) + + var r0 types.ResponseListSnapshots + if rf, ok := ret.Get(0).(func(types.RequestListSnapshots) types.ResponseListSnapshots); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseListSnapshots) + } + + return r0 +} + +// LoadSnapshotChunk provides a mock function with given fields: _a0 +func (_m *Application) LoadSnapshotChunk(_a0 types.RequestLoadSnapshotChunk) types.ResponseLoadSnapshotChunk { + ret := _m.Called(_a0) + + var r0 types.ResponseLoadSnapshotChunk + if rf, ok := ret.Get(0).(func(types.RequestLoadSnapshotChunk) types.ResponseLoadSnapshotChunk); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseLoadSnapshotChunk) + } + + return r0 +} + +// OfferSnapshot provides a mock function with given fields: _a0 +func (_m *Application) OfferSnapshot(_a0 types.RequestOfferSnapshot) types.ResponseOfferSnapshot { + ret := _m.Called(_a0) + + var r0 types.ResponseOfferSnapshot + if rf, ok := ret.Get(0).(func(types.RequestOfferSnapshot) types.ResponseOfferSnapshot); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseOfferSnapshot) + } + + return r0 +} + +// PrepareProposal provides a mock function with given fields: _a0 +func (_m *Application) PrepareProposal(_a0 types.RequestPrepareProposal) types.ResponsePrepareProposal { + ret := _m.Called(_a0) + + var r0 types.ResponsePrepareProposal + if rf, ok := ret.Get(0).(func(types.RequestPrepareProposal) types.ResponsePrepareProposal); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponsePrepareProposal) + } + + return r0 +} + +// Query provides a mock function with given fields: _a0 +func (_m *Application) Query(_a0 types.RequestQuery) types.ResponseQuery { + ret := _m.Called(_a0) + + var r0 types.ResponseQuery + if rf, ok := ret.Get(0).(func(types.RequestQuery) types.ResponseQuery); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseQuery) + } + + return r0 +} + +// SetOption provides a mock function with given fields: _a0 +func (_m *Application) SetOption(_a0 types.RequestSetOption) types.ResponseSetOption { + ret := _m.Called(_a0) + + var r0 types.ResponseSetOption + if rf, ok := ret.Get(0).(func(types.RequestSetOption) types.ResponseSetOption); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseSetOption) + } + + return r0 +} + +type mockConstructorTestingTNewApplication interface { + mock.TestingT + Cleanup(func()) +} + +// NewApplication creates a new instance of Application. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewApplication(t mockConstructorTestingTNewApplication) *Application { + mock := &Application{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/abci/types/mocks/base.go b/abci/types/mocks/base.go new file mode 100644 index 000000000..caf9fc0d2 --- /dev/null +++ b/abci/types/mocks/base.go @@ -0,0 +1,176 @@ +package mocks + +import ( + types "github.com/tendermint/tendermint/abci/types" +) + +// BaseMock provides a wrapper around the generated Application mock and a BaseApplication. +// BaseMock first tries to use the mock's implementation of the method. +// If no functionality was provided for the mock by the user, BaseMock dispatches +// to the BaseApplication and uses its functionality. +// BaseMock allows users to provide mocked functionality for only the methods that matter +// for their test while avoiding a panic if the code calls Application methods that are +// not relevant to the test. +type BaseMock struct { + base *types.BaseApplication + *Application +} + +func NewBaseMock() BaseMock { + return BaseMock{ + base: types.NewBaseApplication(), + Application: new(Application), + } +} + +// Info/Query Connection +// Return application info +func (m BaseMock) Info(input types.RequestInfo) types.ResponseInfo { + var ret types.ResponseInfo + defer func() { + if r := recover(); r != nil { + ret = m.base.Info(input) + } + }() + ret = m.Application.Info(input) + return ret +} + +func (m BaseMock) Query(input types.RequestQuery) types.ResponseQuery { + var ret types.ResponseQuery + defer func() { + if r := recover(); r != nil { + ret = m.base.Query(input) + } + }() + ret = m.Application.Query(input) + return ret +} + +// Mempool Connection +// Validate a tx for the mempool +func (m BaseMock) CheckTx(input types.RequestCheckTx) types.ResponseCheckTx { + var ret types.ResponseCheckTx + defer func() { + if r := recover(); r != nil { + ret = m.base.CheckTx(input) + } + }() + ret = m.Application.CheckTx(input) + return ret +} + +// Consensus Connection +// Initialize blockchain w validators/other info from TendermintCore +func (m BaseMock) InitChain(input types.RequestInitChain) types.ResponseInitChain { + var ret types.ResponseInitChain + defer func() { + if r := recover(); r != nil { + ret = m.base.InitChain(input) + } + }() + ret = m.Application.InitChain(input) + return ret +} + +func (m BaseMock) PrepareProposal(input types.RequestPrepareProposal) types.ResponsePrepareProposal { + var ret types.ResponsePrepareProposal + defer func() { + if r := recover(); r != nil { + ret = m.base.PrepareProposal(input) + } + }() + ret = m.Application.PrepareProposal(input) + return ret +} + +// Commit the state and return the application Merkle root hash +func (m BaseMock) Commit() types.ResponseCommit { + var ret types.ResponseCommit + defer func() { + if r := recover(); r != nil { + ret = m.base.Commit() + } + }() + ret = m.Application.Commit() + return ret +} + +// State Sync Connection +// List available snapshots +func (m BaseMock) ListSnapshots(input types.RequestListSnapshots) types.ResponseListSnapshots { + var ret types.ResponseListSnapshots + defer func() { + if r := recover(); r != nil { + ret = m.base.ListSnapshots(input) + } + }() + ret = m.Application.ListSnapshots(input) + return ret +} + +func (m BaseMock) OfferSnapshot(input types.RequestOfferSnapshot) types.ResponseOfferSnapshot { + var ret types.ResponseOfferSnapshot + defer func() { + if r := recover(); r != nil { + ret = m.base.OfferSnapshot(input) + } + }() + ret = m.Application.OfferSnapshot(input) + return ret +} + +func (m BaseMock) LoadSnapshotChunk(input types.RequestLoadSnapshotChunk) types.ResponseLoadSnapshotChunk { + var ret types.ResponseLoadSnapshotChunk + defer func() { + if r := recover(); r != nil { + ret = m.base.LoadSnapshotChunk(input) + } + }() + ret = m.Application.LoadSnapshotChunk(input) + return ret +} + +func (m BaseMock) ApplySnapshotChunk(input types.RequestApplySnapshotChunk) types.ResponseApplySnapshotChunk { + var ret types.ResponseApplySnapshotChunk + defer func() { + if r := recover(); r != nil { + ret = m.base.ApplySnapshotChunk(input) + } + }() + ret = m.Application.ApplySnapshotChunk(input) + return ret +} + +func (m BaseMock) BeginBlock(input types.RequestBeginBlock) types.ResponseBeginBlock { + var ret types.ResponseBeginBlock + defer func() { + if r := recover(); r != nil { + ret = m.base.BeginBlock(input) + } + }() + ret = m.Application.BeginBlock(input) + return ret +} + +func (m BaseMock) DeliverTx(input types.RequestDeliverTx) types.ResponseDeliverTx { + var ret types.ResponseDeliverTx + defer func() { + if r := recover(); r != nil { + ret = m.base.DeliverTx(input) + } + }() + ret = m.Application.DeliverTx(input) + return ret +} + +func (m BaseMock) EndBlock(input types.RequestEndBlock) types.ResponseEndBlock { + var ret types.ResponseEndBlock + defer func() { + if r := recover(); r != nil { + ret = m.base.EndBlock(input) + } + }() + ret = m.Application.EndBlock(input) + return ret +} diff --git a/abci/types/result.go b/abci/types/types.go similarity index 100% rename from abci/types/result.go rename to abci/types/types.go diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 5e5f95b38..551e0c7a6 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -188,6 +188,38 @@ func (ResponseProcessProposal_ProposalStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor_252557cfdd89a31a, []int{36, 0} } +// TxAction contains App-provided information on what to do with a transaction that is part of a raw proposal +type TxRecord_TxAction int32 + +const ( + TxRecord_UNKNOWN TxRecord_TxAction = 0 + TxRecord_UNMODIFIED TxRecord_TxAction = 1 + TxRecord_ADDED TxRecord_TxAction = 2 + TxRecord_REMOVED TxRecord_TxAction = 3 +) + +var TxRecord_TxAction_name = map[int32]string{ + 0: "UNKNOWN", + 1: "UNMODIFIED", + 2: "ADDED", + 3: "REMOVED", +} + +var TxRecord_TxAction_value = map[string]int32{ + "UNKNOWN": 0, + "UNMODIFIED": 1, + "ADDED": 2, + "REMOVED": 3, +} + +func (x TxRecord_TxAction) String() string { + return proto.EnumName(TxRecord_TxAction_name, int32(x)) +} + +func (TxRecord_TxAction) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{42, 0} +} + type Request struct { // Types that are valid to be assigned to Value: // *Request_Echo @@ -1270,12 +1302,15 @@ func (m *RequestApplySnapshotChunk) GetSender() string { } type RequestPrepareProposal struct { - // block_data is an array of transactions that will be included in a block, + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + Header types1.Header `protobuf:"bytes,2,opt,name=header,proto3" json:"header"` + // txs is an array of transactions that will be included in a block, // sent to the app for possible modifications. - // applications can not exceed the size of the data passed to it. - BlockData [][]byte `protobuf:"bytes,1,rep,name=block_data,json=blockData,proto3" json:"block_data,omitempty"` - // If an application decides to populate block_data with extra information, they can not exceed this value. - BlockDataSize int64 `protobuf:"varint,2,opt,name=block_data_size,json=blockDataSize,proto3" json:"block_data_size,omitempty"` + Txs [][]byte `protobuf:"bytes,3,rep,name=txs,proto3" json:"txs,omitempty"` + LocalLastCommit ExtendedCommitInfo `protobuf:"bytes,4,opt,name=local_last_commit,json=localLastCommit,proto3" json:"local_last_commit"` + ByzantineValidators []Evidence `protobuf:"bytes,5,rep,name=byzantine_validators,json=byzantineValidators,proto3" json:"byzantine_validators"` + // the modified transactions cannot exceed this size. + MaxTxBytes int64 `protobuf:"varint,6,opt,name=max_tx_bytes,json=maxTxBytes,proto3" json:"max_tx_bytes,omitempty"` } func (m *RequestPrepareProposal) Reset() { *m = RequestPrepareProposal{} } @@ -1311,16 +1346,44 @@ func (m *RequestPrepareProposal) XXX_DiscardUnknown() { var xxx_messageInfo_RequestPrepareProposal proto.InternalMessageInfo -func (m *RequestPrepareProposal) GetBlockData() [][]byte { +func (m *RequestPrepareProposal) GetHash() []byte { if m != nil { - return m.BlockData + return m.Hash } return nil } -func (m *RequestPrepareProposal) GetBlockDataSize() int64 { +func (m *RequestPrepareProposal) GetHeader() types1.Header { if m != nil { - return m.BlockDataSize + return m.Header + } + return types1.Header{} +} + +func (m *RequestPrepareProposal) GetTxs() [][]byte { + if m != nil { + return m.Txs + } + return nil +} + +func (m *RequestPrepareProposal) GetLocalLastCommit() ExtendedCommitInfo { + if m != nil { + return m.LocalLastCommit + } + return ExtendedCommitInfo{} +} + +func (m *RequestPrepareProposal) GetByzantineValidators() []Evidence { + if m != nil { + return m.ByzantineValidators + } + return nil +} + +func (m *RequestPrepareProposal) GetMaxTxBytes() int64 { + if m != nil { + return m.MaxTxBytes } return 0 } @@ -2728,7 +2791,7 @@ func (m *ResponseApplySnapshotChunk) GetRejectSenders() []string { } type ResponsePrepareProposal struct { - BlockData [][]byte `protobuf:"bytes,1,rep,name=block_data,json=blockData,proto3" json:"block_data,omitempty"` + TxRecords []*TxRecord `protobuf:"bytes,1,rep,name=tx_records,json=txRecords,proto3" json:"tx_records,omitempty"` } func (m *ResponsePrepareProposal) Reset() { *m = ResponsePrepareProposal{} } @@ -2764,9 +2827,9 @@ func (m *ResponsePrepareProposal) XXX_DiscardUnknown() { var xxx_messageInfo_ResponsePrepareProposal proto.InternalMessageInfo -func (m *ResponsePrepareProposal) GetBlockData() [][]byte { +func (m *ResponsePrepareProposal) GetTxRecords() []*TxRecord { if m != nil { - return m.BlockData + return m.TxRecords } return nil } @@ -2992,6 +3055,58 @@ func (m *CommitInfo) GetVotes() []VoteInfo { return nil } +type ExtendedCommitInfo struct { + Round int32 `protobuf:"varint,1,opt,name=round,proto3" json:"round,omitempty"` + Votes []ExtendedVoteInfo `protobuf:"bytes,2,rep,name=votes,proto3" json:"votes"` +} + +func (m *ExtendedCommitInfo) Reset() { *m = ExtendedCommitInfo{} } +func (m *ExtendedCommitInfo) String() string { return proto.CompactTextString(m) } +func (*ExtendedCommitInfo) ProtoMessage() {} +func (*ExtendedCommitInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{38} +} +func (m *ExtendedCommitInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExtendedCommitInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExtendedCommitInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExtendedCommitInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtendedCommitInfo.Merge(m, src) +} +func (m *ExtendedCommitInfo) XXX_Size() int { + return m.Size() +} +func (m *ExtendedCommitInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ExtendedCommitInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtendedCommitInfo proto.InternalMessageInfo + +func (m *ExtendedCommitInfo) GetRound() int32 { + if m != nil { + return m.Round + } + return 0 +} + +func (m *ExtendedCommitInfo) GetVotes() []ExtendedVoteInfo { + if m != nil { + return m.Votes + } + return nil +} + // Event allows application developers to attach additional information to // ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. // Later, transactions may be queried using these events. @@ -3004,7 +3119,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{40} + return fileDescriptor_252557cfdd89a31a, []int{39} } func (m *Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3058,7 +3173,7 @@ func (m *EventAttribute) Reset() { *m = EventAttribute{} } func (m *EventAttribute) String() string { return proto.CompactTextString(m) } func (*EventAttribute) ProtoMessage() {} func (*EventAttribute) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{41} + return fileDescriptor_252557cfdd89a31a, []int{40} } func (m *EventAttribute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3122,7 +3237,7 @@ func (m *TxResult) Reset() { *m = TxResult{} } func (m *TxResult) String() string { return proto.CompactTextString(m) } func (*TxResult) ProtoMessage() {} func (*TxResult) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{42} + return fileDescriptor_252557cfdd89a31a, []int{41} } func (m *TxResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3179,6 +3294,58 @@ func (m *TxResult) GetResult() ResponseDeliverTx { return ResponseDeliverTx{} } +type TxRecord struct { + Action TxRecord_TxAction `protobuf:"varint,1,opt,name=action,proto3,enum=tendermint.abci.TxRecord_TxAction" json:"action,omitempty"` + Tx []byte `protobuf:"bytes,2,opt,name=tx,proto3" json:"tx,omitempty"` +} + +func (m *TxRecord) Reset() { *m = TxRecord{} } +func (m *TxRecord) String() string { return proto.CompactTextString(m) } +func (*TxRecord) ProtoMessage() {} +func (*TxRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{42} +} +func (m *TxRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TxRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TxRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TxRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_TxRecord.Merge(m, src) +} +func (m *TxRecord) XXX_Size() int { + return m.Size() +} +func (m *TxRecord) XXX_DiscardUnknown() { + xxx_messageInfo_TxRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_TxRecord proto.InternalMessageInfo + +func (m *TxRecord) GetAction() TxRecord_TxAction { + if m != nil { + return m.Action + } + return TxRecord_UNKNOWN +} + +func (m *TxRecord) GetTx() []byte { + if m != nil { + return m.Tx + } + return nil +} + // Validator type Validator struct { Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` @@ -3339,6 +3506,66 @@ func (m *VoteInfo) GetSignedLastBlock() bool { return false } +type ExtendedVoteInfo struct { + Validator Validator `protobuf:"bytes,1,opt,name=validator,proto3" json:"validator"` + SignedLastBlock bool `protobuf:"varint,2,opt,name=signed_last_block,json=signedLastBlock,proto3" json:"signed_last_block,omitempty"` + VoteExtension []byte `protobuf:"bytes,3,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` +} + +func (m *ExtendedVoteInfo) Reset() { *m = ExtendedVoteInfo{} } +func (m *ExtendedVoteInfo) String() string { return proto.CompactTextString(m) } +func (*ExtendedVoteInfo) ProtoMessage() {} +func (*ExtendedVoteInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{46} +} +func (m *ExtendedVoteInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExtendedVoteInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExtendedVoteInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExtendedVoteInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtendedVoteInfo.Merge(m, src) +} +func (m *ExtendedVoteInfo) XXX_Size() int { + return m.Size() +} +func (m *ExtendedVoteInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ExtendedVoteInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtendedVoteInfo proto.InternalMessageInfo + +func (m *ExtendedVoteInfo) GetValidator() Validator { + if m != nil { + return m.Validator + } + return Validator{} +} + +func (m *ExtendedVoteInfo) GetSignedLastBlock() bool { + if m != nil { + return m.SignedLastBlock + } + return false +} + +func (m *ExtendedVoteInfo) GetVoteExtension() []byte { + if m != nil { + return m.VoteExtension + } + return nil +} + type Evidence struct { Type EvidenceType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.abci.EvidenceType" json:"type,omitempty"` // The offending validator @@ -3357,7 +3584,7 @@ func (m *Evidence) Reset() { *m = Evidence{} } func (m *Evidence) String() string { return proto.CompactTextString(m) } func (*Evidence) ProtoMessage() {} func (*Evidence) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{46} + return fileDescriptor_252557cfdd89a31a, []int{47} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3433,7 +3660,7 @@ func (m *Snapshot) Reset() { *m = Snapshot{} } func (m *Snapshot) String() string { return proto.CompactTextString(m) } func (*Snapshot) ProtoMessage() {} func (*Snapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{47} + return fileDescriptor_252557cfdd89a31a, []int{48} } func (m *Snapshot) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3502,7 +3729,7 @@ func init() { proto.RegisterEnum("tendermint.abci.EvidenceType", EvidenceType_name, EvidenceType_value) proto.RegisterEnum("tendermint.abci.ResponseOfferSnapshot_Result", ResponseOfferSnapshot_Result_name, ResponseOfferSnapshot_Result_value) proto.RegisterEnum("tendermint.abci.ResponseApplySnapshotChunk_Result", ResponseApplySnapshotChunk_Result_name, ResponseApplySnapshotChunk_Result_value) - proto.RegisterEnum("tendermint.abci.ResponseProcessProposal_ProposalStatus", ResponseProcessProposal_ProposalStatus_name, ResponseProcessProposal_ProposalStatus_value) + proto.RegisterEnum("tendermint.abci.TxRecord_TxAction", TxRecord_TxAction_name, TxRecord_TxAction_value) proto.RegisterType((*Request)(nil), "tendermint.abci.Request") proto.RegisterType((*RequestEcho)(nil), "tendermint.abci.RequestEcho") proto.RegisterType((*RequestFlush)(nil), "tendermint.abci.RequestFlush") @@ -3542,13 +3769,15 @@ func init() { proto.RegisterType((*ResponseProcessProposal)(nil), "tendermint.abci.ResponseProcessProposal") proto.RegisterType((*ConsensusParams)(nil), "tendermint.abci.ConsensusParams") proto.RegisterType((*BlockParams)(nil), "tendermint.abci.BlockParams") - proto.RegisterType((*CommitInfo)(nil), "tendermint.abci.CommitInfo") + proto.RegisterType((*ExtendedCommitInfo)(nil), "tendermint.abci.ExtendedCommitInfo") proto.RegisterType((*Event)(nil), "tendermint.abci.Event") proto.RegisterType((*EventAttribute)(nil), "tendermint.abci.EventAttribute") proto.RegisterType((*TxResult)(nil), "tendermint.abci.TxResult") + proto.RegisterType((*TxRecord)(nil), "tendermint.abci.TxRecord") proto.RegisterType((*Validator)(nil), "tendermint.abci.Validator") proto.RegisterType((*ValidatorUpdate)(nil), "tendermint.abci.ValidatorUpdate") proto.RegisterType((*VoteInfo)(nil), "tendermint.abci.VoteInfo") + proto.RegisterType((*ExtendedVoteInfo)(nil), "tendermint.abci.ExtendedVoteInfo") proto.RegisterType((*Evidence)(nil), "tendermint.abci.Evidence") proto.RegisterType((*Snapshot)(nil), "tendermint.abci.Snapshot") } @@ -3556,200 +3785,200 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3084 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0xcd, 0x93, 0x1b, 0xc5, - 0x15, 0xd7, 0xb7, 0x34, 0x4f, 0xab, 0x8f, 0x6d, 0x2f, 0xb6, 0x10, 0xf6, 0xae, 0x19, 0x17, 0x60, - 0x1b, 0xd8, 0x85, 0xa5, 0x0c, 0x26, 0x90, 0x80, 0x24, 0xcb, 0x68, 0xf1, 0xb2, 0xbb, 0x99, 0x95, - 0x4d, 0xc8, 0x87, 0x87, 0x91, 0xd4, 0x2b, 0x0d, 0x96, 0x66, 0x86, 0x99, 0xd6, 0xb2, 0xeb, 0x53, - 0x2a, 0x55, 0x5c, 0xc8, 0x85, 0xaa, 0x5c, 0x72, 0xe1, 0x90, 0xff, 0x22, 0x97, 0xe4, 0x92, 0x0b, - 0x55, 0x39, 0x84, 0x63, 0x0e, 0x29, 0x92, 0x82, 0x5b, 0xfe, 0x81, 0x9c, 0x52, 0x49, 0xf5, 0xc7, - 0x7c, 0x49, 0x9a, 0xd5, 0x2c, 0xe4, 0x96, 0x5b, 0xf7, 0xeb, 0xf7, 0xde, 0x4c, 0xf7, 0x74, 0xbf, - 0xf7, 0x7e, 0xbf, 0x69, 0x78, 0x8a, 0x60, 0x63, 0x80, 0xed, 0x89, 0x6e, 0x90, 0x2d, 0xad, 0xd7, - 0xd7, 0xb7, 0xc8, 0xa9, 0x85, 0x9d, 0x4d, 0xcb, 0x36, 0x89, 0x89, 0x2a, 0xfe, 0xe0, 0x26, 0x1d, - 0xac, 0x5f, 0x09, 0x68, 0xf7, 0xed, 0x53, 0x8b, 0x98, 0x5b, 0x96, 0x6d, 0x9a, 0x47, 0x5c, 0xbf, - 0x7e, 0x39, 0x30, 0xcc, 0xfc, 0x04, 0xbd, 0x85, 0x46, 0x85, 0xf1, 0x23, 0x7c, 0xea, 0x8e, 0x5e, - 0x99, 0xb3, 0xb5, 0x34, 0x5b, 0x9b, 0xb8, 0xc3, 0x1b, 0x43, 0xd3, 0x1c, 0x8e, 0xf1, 0x16, 0xeb, - 0xf5, 0xa6, 0x47, 0x5b, 0x44, 0x9f, 0x60, 0x87, 0x68, 0x13, 0x4b, 0x28, 0xac, 0x0d, 0xcd, 0xa1, - 0xc9, 0x9a, 0x5b, 0xb4, 0xc5, 0xa5, 0xf2, 0x1f, 0x24, 0xc8, 0x2b, 0xf8, 0xe3, 0x29, 0x76, 0x08, - 0xda, 0x86, 0x0c, 0xee, 0x8f, 0xcc, 0x5a, 0xf2, 0x6a, 0xf2, 0x7a, 0x71, 0xfb, 0xf2, 0xe6, 0xcc, - 0xe4, 0x36, 0x85, 0x5e, 0xbb, 0x3f, 0x32, 0x3b, 0x09, 0x85, 0xe9, 0xa2, 0x5b, 0x90, 0x3d, 0x1a, - 0x4f, 0x9d, 0x51, 0x2d, 0xc5, 0x8c, 0xae, 0x44, 0x19, 0xdd, 0xa5, 0x4a, 0x9d, 0x84, 0xc2, 0xb5, - 0xe9, 0xa3, 0x74, 0xe3, 0xc8, 0xac, 0xa5, 0xcf, 0x7e, 0xd4, 0x8e, 0x71, 0xc4, 0x1e, 0x45, 0x75, - 0x51, 0x13, 0xc0, 0xc1, 0x44, 0x35, 0x2d, 0xa2, 0x9b, 0x46, 0x2d, 0xc3, 0x2c, 0x9f, 0x8e, 0xb2, - 0x3c, 0xc4, 0x64, 0x9f, 0x29, 0x76, 0x12, 0x8a, 0xe4, 0xb8, 0x1d, 0xea, 0x43, 0x37, 0x74, 0xa2, - 0xf6, 0x47, 0x9a, 0x6e, 0xd4, 0xb2, 0x67, 0xfb, 0xd8, 0x31, 0x74, 0xd2, 0xa2, 0x8a, 0xd4, 0x87, - 0xee, 0x76, 0xe8, 0x94, 0x3f, 0x9e, 0x62, 0xfb, 0xb4, 0x96, 0x3b, 0x7b, 0xca, 0x3f, 0xa6, 0x4a, - 0x74, 0xca, 0x4c, 0x1b, 0xb5, 0xa1, 0xd8, 0xc3, 0x43, 0xdd, 0x50, 0x7b, 0x63, 0xb3, 0xff, 0xa8, - 0x96, 0x67, 0xc6, 0x72, 0x94, 0x71, 0x93, 0xaa, 0x36, 0xa9, 0x66, 0x27, 0xa1, 0x40, 0xcf, 0xeb, - 0xa1, 0x37, 0xa1, 0xd0, 0x1f, 0xe1, 0xfe, 0x23, 0x95, 0x9c, 0xd4, 0x0a, 0xcc, 0xc7, 0x46, 0x94, - 0x8f, 0x16, 0xd5, 0xeb, 0x9e, 0x74, 0x12, 0x4a, 0xbe, 0xcf, 0x9b, 0x74, 0xfe, 0x03, 0x3c, 0xd6, - 0x8f, 0xb1, 0x4d, 0xed, 0xa5, 0xb3, 0xe7, 0x7f, 0x87, 0x6b, 0x32, 0x0f, 0xd2, 0xc0, 0xed, 0xa0, - 0xb7, 0x40, 0xc2, 0xc6, 0x40, 0x4c, 0x03, 0x98, 0x8b, 0xab, 0x91, 0x7b, 0xc5, 0x18, 0xb8, 0x93, - 0x28, 0x60, 0xd1, 0x46, 0xb7, 0x21, 0xd7, 0x37, 0x27, 0x13, 0x9d, 0xd4, 0x8a, 0xcc, 0x7a, 0x3d, - 0x72, 0x02, 0x4c, 0xab, 0x93, 0x50, 0x84, 0x3e, 0xda, 0x83, 0xf2, 0x58, 0x77, 0x88, 0xea, 0x18, - 0x9a, 0xe5, 0x8c, 0x4c, 0xe2, 0xd4, 0x56, 0x98, 0x87, 0x67, 0xa2, 0x3c, 0xec, 0xea, 0x0e, 0x39, - 0x74, 0x95, 0x3b, 0x09, 0xa5, 0x34, 0x0e, 0x0a, 0xa8, 0x3f, 0xf3, 0xe8, 0x08, 0xdb, 0x9e, 0xc3, - 0x5a, 0xe9, 0x6c, 0x7f, 0xfb, 0x54, 0xdb, 0xb5, 0xa7, 0xfe, 0xcc, 0xa0, 0x00, 0xfd, 0x0c, 0x2e, - 0x8c, 0x4d, 0x6d, 0xe0, 0xb9, 0x53, 0xfb, 0xa3, 0xa9, 0xf1, 0xa8, 0x56, 0x66, 0x4e, 0x6f, 0x44, - 0xbe, 0xa4, 0xa9, 0x0d, 0x5c, 0x17, 0x2d, 0x6a, 0xd0, 0x49, 0x28, 0xab, 0xe3, 0x59, 0x21, 0x7a, - 0x08, 0x6b, 0x9a, 0x65, 0x8d, 0x4f, 0x67, 0xbd, 0x57, 0x98, 0xf7, 0x9b, 0x51, 0xde, 0x1b, 0xd4, - 0x66, 0xd6, 0x3d, 0xd2, 0xe6, 0xa4, 0xa8, 0x0b, 0x55, 0xcb, 0xc6, 0x96, 0x66, 0x63, 0xd5, 0xb2, - 0x4d, 0xcb, 0x74, 0xb4, 0x71, 0xad, 0xca, 0x7c, 0x3f, 0x17, 0xe5, 0xfb, 0x80, 0xeb, 0x1f, 0x08, - 0xf5, 0x4e, 0x42, 0xa9, 0x58, 0x61, 0x11, 0xf7, 0x6a, 0xf6, 0xb1, 0xe3, 0xf8, 0x5e, 0x57, 0x97, - 0x79, 0x65, 0xfa, 0x61, 0xaf, 0x21, 0x51, 0x33, 0x0f, 0xd9, 0x63, 0x6d, 0x3c, 0xc5, 0xf2, 0x73, - 0x50, 0x0c, 0x84, 0x25, 0x54, 0x83, 0xfc, 0x04, 0x3b, 0x8e, 0x36, 0xc4, 0x2c, 0x8a, 0x49, 0x8a, - 0xdb, 0x95, 0xcb, 0xb0, 0x12, 0x0c, 0x45, 0xf2, 0xc4, 0x33, 0xa4, 0x41, 0x86, 0x1a, 0x1e, 0x63, - 0xdb, 0xa1, 0x91, 0x45, 0x18, 0x8a, 0x2e, 0xba, 0x06, 0x25, 0xb6, 0xd5, 0x55, 0x77, 0x9c, 0x46, - 0xba, 0x8c, 0xb2, 0xc2, 0x84, 0x0f, 0x84, 0xd2, 0x06, 0x14, 0xad, 0x6d, 0xcb, 0x53, 0x49, 0x33, - 0x15, 0xb0, 0xb6, 0x2d, 0xa1, 0x20, 0xff, 0x00, 0xaa, 0xb3, 0x91, 0x09, 0x55, 0x21, 0xfd, 0x08, - 0x9f, 0x8a, 0xe7, 0xd1, 0x26, 0x5a, 0x13, 0xd3, 0x62, 0xcf, 0x90, 0x14, 0x31, 0xc7, 0x3f, 0xa7, - 0x3c, 0x63, 0x2f, 0x24, 0xa1, 0xdb, 0x90, 0xa1, 0x11, 0x5e, 0x04, 0xeb, 0xfa, 0x26, 0x0f, 0xff, - 0x9b, 0x6e, 0xf8, 0xdf, 0xec, 0xba, 0xe1, 0xbf, 0x59, 0xf8, 0xf2, 0xeb, 0x8d, 0xc4, 0xe7, 0x7f, - 0xdf, 0x48, 0x2a, 0xcc, 0x02, 0x3d, 0x49, 0x23, 0x88, 0xa6, 0x1b, 0xaa, 0x3e, 0x10, 0xcf, 0xc9, - 0xb3, 0xfe, 0xce, 0x00, 0xdd, 0x83, 0x6a, 0xdf, 0x34, 0x1c, 0x6c, 0x38, 0x53, 0x47, 0xe5, 0xe9, - 0x45, 0x84, 0xe8, 0xf9, 0x13, 0xde, 0x72, 0x15, 0x0f, 0x98, 0x9e, 0x52, 0xe9, 0x87, 0x05, 0xe8, - 0x2e, 0xc0, 0xb1, 0x36, 0xd6, 0x07, 0x1a, 0x31, 0x6d, 0xa7, 0x96, 0xb9, 0x9a, 0x5e, 0xe8, 0xe6, - 0x81, 0xab, 0x72, 0xdf, 0x1a, 0x68, 0x04, 0x37, 0x33, 0xf4, 0x6d, 0x95, 0x80, 0x25, 0x7a, 0x16, - 0x2a, 0x9a, 0x65, 0xa9, 0x0e, 0xd1, 0x08, 0x56, 0x7b, 0xa7, 0x04, 0x3b, 0x2c, 0x70, 0xaf, 0x28, - 0x25, 0xcd, 0xb2, 0x0e, 0xa9, 0xb4, 0x49, 0x85, 0xe8, 0x19, 0x28, 0xd3, 0x20, 0xad, 0x6b, 0x63, - 0x75, 0x84, 0xf5, 0xe1, 0x88, 0xb0, 0x00, 0x9d, 0x56, 0x4a, 0x42, 0xda, 0x61, 0x42, 0x79, 0xe0, - 0x6d, 0x04, 0x16, 0xa0, 0x11, 0x82, 0xcc, 0x40, 0x23, 0x1a, 0x5b, 0xc8, 0x15, 0x85, 0xb5, 0xa9, - 0xcc, 0xd2, 0xc8, 0x48, 0x2c, 0x0f, 0x6b, 0xa3, 0x8b, 0x90, 0x13, 0x6e, 0xd3, 0xcc, 0xad, 0xe8, - 0xd1, 0x6f, 0x66, 0xd9, 0xe6, 0x31, 0x66, 0x19, 0xa9, 0xa0, 0xf0, 0x8e, 0xfc, 0xcb, 0x14, 0xac, - 0xce, 0x85, 0x72, 0xea, 0x77, 0xa4, 0x39, 0x23, 0xf7, 0x59, 0xb4, 0x8d, 0x5e, 0xa5, 0x7e, 0xb5, - 0x01, 0xb6, 0x45, 0x0a, 0xad, 0x05, 0x97, 0x88, 0x97, 0x07, 0x1d, 0x36, 0x2e, 0x96, 0x46, 0x68, - 0xd3, 0x6f, 0x35, 0xd6, 0x1c, 0xa2, 0xf2, 0xd0, 0xa8, 0x06, 0xd2, 0xe9, 0x53, 0x0b, 0xbe, 0x15, - 0xd5, 0xa1, 0x1b, 0x5d, 0x38, 0x29, 0x53, 0x53, 0x5f, 0x8a, 0x14, 0x58, 0xeb, 0x9d, 0x3e, 0xd6, - 0x0c, 0xa2, 0x1b, 0x58, 0x9d, 0xfb, 0x6a, 0x4f, 0xce, 0x39, 0x6c, 0x1f, 0xeb, 0x03, 0x6c, 0xf4, - 0xdd, 0xcf, 0x75, 0xc1, 0x33, 0xf6, 0x3e, 0xa7, 0x23, 0x2b, 0x50, 0x0e, 0x27, 0x22, 0x54, 0x86, - 0x14, 0x39, 0x11, 0x93, 0x4f, 0x91, 0x13, 0xf4, 0x12, 0x64, 0xe8, 0x04, 0xd9, 0xc4, 0xcb, 0x0b, - 0xaa, 0x00, 0x61, 0xd7, 0x3d, 0xb5, 0xb0, 0xc2, 0x34, 0x65, 0xd9, 0x3b, 0x09, 0x5e, 0x72, 0x9a, - 0xf5, 0x2a, 0xdf, 0x80, 0xca, 0x4c, 0xf6, 0x09, 0x7c, 0xbb, 0x64, 0xf0, 0xdb, 0xc9, 0x15, 0x28, - 0x85, 0x52, 0x8d, 0x7c, 0x11, 0xd6, 0x16, 0x65, 0x0e, 0x79, 0xe4, 0xc9, 0x43, 0x19, 0x00, 0xdd, - 0x82, 0x82, 0x97, 0x3a, 0xf8, 0x49, 0x9c, 0x5f, 0x2b, 0x57, 0x59, 0xf1, 0x54, 0xe9, 0x11, 0xa4, - 0x5b, 0x9a, 0xed, 0x85, 0x14, 0x7b, 0xf1, 0xbc, 0x66, 0x59, 0x1d, 0xcd, 0x19, 0xc9, 0x1f, 0x42, - 0x2d, 0x2a, 0x2d, 0xcc, 0x4c, 0x23, 0xe3, 0x6d, 0xc1, 0x8b, 0x90, 0x3b, 0x32, 0xed, 0x89, 0x46, - 0x98, 0xb3, 0x92, 0x22, 0x7a, 0x74, 0x6b, 0xf2, 0x14, 0x91, 0x66, 0x62, 0xde, 0x91, 0x55, 0x78, - 0x32, 0x32, 0x35, 0x50, 0x13, 0xdd, 0x18, 0x60, 0xbe, 0x9e, 0x25, 0x85, 0x77, 0x7c, 0x47, 0xfc, - 0x65, 0x79, 0x87, 0x3e, 0xd6, 0x61, 0x73, 0x65, 0xfe, 0x25, 0x45, 0xf4, 0x64, 0x15, 0x2e, 0x2e, - 0xce, 0x0f, 0xe8, 0x0a, 0x00, 0x8f, 0xa5, 0xe2, 0xc4, 0xa5, 0xaf, 0xaf, 0x28, 0x12, 0x93, 0xdc, - 0xa1, 0xc7, 0xee, 0x59, 0xa8, 0xf8, 0xc3, 0xaa, 0xa3, 0x3f, 0xe6, 0x5b, 0x23, 0xad, 0x94, 0x3c, - 0x9d, 0x43, 0xfd, 0x31, 0x96, 0x3f, 0x4d, 0x07, 0x9e, 0x10, 0x4a, 0x0c, 0x34, 0xa6, 0x92, 0x13, - 0x47, 0xb8, 0xa6, 0x4d, 0x74, 0x08, 0x6b, 0x3c, 0xf1, 0xe0, 0x81, 0x1a, 0x38, 0x30, 0xe2, 0xb4, - 0xc5, 0x38, 0x2b, 0xc8, 0x35, 0xdf, 0xf5, 0xce, 0x0c, 0x6a, 0x40, 0x71, 0xa2, 0x3b, 0x3d, 0x3c, - 0xd2, 0x8e, 0x75, 0x93, 0xce, 0x3f, 0xd6, 0x31, 0x09, 0xda, 0x78, 0xb1, 0x20, 0x13, 0x88, 0x05, - 0xfe, 0x07, 0xce, 0x86, 0x62, 0x8c, 0x1b, 0xec, 0x73, 0xe7, 0x0e, 0xf6, 0x2f, 0xc1, 0x9a, 0x81, - 0x4f, 0x48, 0xe0, 0x4c, 0xf3, 0x5d, 0x97, 0x67, 0x4f, 0x45, 0x74, 0xcc, 0x3f, 0xb2, 0x74, 0x03, - 0xa2, 0x1b, 0x2c, 0x61, 0xd3, 0x09, 0xdb, 0xaa, 0x36, 0x18, 0xd8, 0xd8, 0x71, 0x58, 0xa1, 0xb9, - 0xc2, 0xb2, 0x30, 0x93, 0x37, 0xb8, 0x58, 0xfe, 0x0d, 0x40, 0x41, 0xc1, 0x8e, 0x45, 0x03, 0x3f, - 0x6a, 0x82, 0x84, 0x4f, 0xfa, 0x98, 0x57, 0xe7, 0xc9, 0xc8, 0xea, 0x96, 0x6b, 0xb7, 0x5d, 0x4d, - 0x5a, 0x5a, 0x7a, 0x66, 0xe8, 0x15, 0x81, 0x40, 0xa2, 0xc1, 0x84, 0x30, 0x0f, 0x42, 0x90, 0x57, - 0x5d, 0x08, 0x92, 0x8e, 0xac, 0x26, 0xb9, 0xd5, 0x0c, 0x06, 0x79, 0x45, 0x60, 0x90, 0xcc, 0x92, - 0x87, 0x85, 0x40, 0x48, 0x2b, 0x04, 0x42, 0xb2, 0x4b, 0xa6, 0x19, 0x81, 0x42, 0x5a, 0x21, 0x14, - 0x92, 0x5b, 0xe2, 0x24, 0x02, 0x86, 0xbc, 0xea, 0xc2, 0x90, 0xfc, 0x92, 0x69, 0xcf, 0xe0, 0x90, - 0xbb, 0x61, 0x1c, 0xc2, 0x31, 0xc4, 0xb5, 0x48, 0xeb, 0x48, 0x20, 0xf2, 0xc3, 0x00, 0x10, 0x91, - 0x22, 0x51, 0x00, 0x77, 0xb2, 0x00, 0x89, 0xb4, 0x42, 0x48, 0x04, 0x96, 0xac, 0x41, 0x04, 0x14, - 0x79, 0x3b, 0x08, 0x45, 0x8a, 0x91, 0x68, 0x46, 0x6c, 0x9a, 0x45, 0x58, 0xe4, 0x75, 0x0f, 0x8b, - 0xac, 0x44, 0x82, 0x29, 0x31, 0x87, 0x59, 0x30, 0xb2, 0x3f, 0x07, 0x46, 0x38, 0x78, 0x78, 0x36, - 0xd2, 0xc5, 0x12, 0x34, 0xb2, 0x3f, 0x87, 0x46, 0xca, 0x4b, 0x1c, 0x2e, 0x81, 0x23, 0x3f, 0x5f, - 0x0c, 0x47, 0xa2, 0x01, 0x83, 0x78, 0xcd, 0x78, 0x78, 0x44, 0x8d, 0xc0, 0x23, 0x1c, 0x33, 0x3c, - 0x1f, 0xe9, 0x3e, 0x36, 0x20, 0xb9, 0xbf, 0x00, 0x90, 0x70, 0xe8, 0x70, 0x3d, 0xd2, 0x79, 0x0c, - 0x44, 0x72, 0x7f, 0x01, 0x22, 0x41, 0x4b, 0xdd, 0xc6, 0x87, 0x24, 0x37, 0x68, 0xe5, 0x37, 0x13, - 0xe6, 0x68, 0x06, 0xc5, 0xb6, 0x6d, 0xda, 0xa2, 0xda, 0xe7, 0x1d, 0xf9, 0x3a, 0xad, 0x45, 0xfd, - 0x90, 0x76, 0x06, 0x7c, 0x61, 0x95, 0x4a, 0x20, 0x8c, 0xc9, 0xbf, 0x4f, 0xfa, 0xb6, 0xac, 0x84, - 0x0b, 0xd6, 0xb1, 0x92, 0xa8, 0x63, 0x03, 0xa8, 0x26, 0x15, 0x46, 0x35, 0x1b, 0x50, 0xa4, 0x15, - 0xc8, 0x0c, 0x60, 0xd1, 0x2c, 0x17, 0xb0, 0xa0, 0x9b, 0xb0, 0xca, 0xb2, 0x25, 0x4f, 0xc8, 0x22, - 0x2b, 0x65, 0x58, 0x56, 0xaa, 0xd0, 0x01, 0x7e, 0x94, 0x78, 0x7a, 0x7a, 0x11, 0x2e, 0x04, 0x74, - 0xbd, 0xca, 0x86, 0x57, 0xe9, 0x55, 0x4f, 0xbb, 0x21, 0x4a, 0x9c, 0xf7, 0xfc, 0x05, 0xf2, 0xc1, - 0x10, 0x82, 0x4c, 0xdf, 0x1c, 0x60, 0x51, 0x77, 0xb0, 0x36, 0x4d, 0xe6, 0x63, 0x73, 0x28, 0xaa, - 0x0b, 0xda, 0xa4, 0x5a, 0x5e, 0xcc, 0x96, 0x78, 0x48, 0x96, 0xff, 0x94, 0xf4, 0xfd, 0xf9, 0xf8, - 0x68, 0x11, 0x94, 0x49, 0xfe, 0x6f, 0xa0, 0x4c, 0xea, 0x3b, 0x43, 0x99, 0x60, 0xdd, 0x97, 0x0e, - 0xd7, 0x7d, 0xff, 0x4a, 0xfa, 0x5f, 0xd8, 0x03, 0x26, 0xdf, 0x6d, 0x45, 0xfc, 0x22, 0x8e, 0x57, - 0x11, 0xa2, 0x88, 0x13, 0x70, 0x33, 0xc7, 0x9e, 0x1b, 0x86, 0x9b, 0xbc, 0x1a, 0xe0, 0x1d, 0x74, - 0x1b, 0x24, 0xc6, 0x59, 0xaa, 0xa6, 0xe5, 0x88, 0xf4, 0x10, 0xaa, 0x92, 0x38, 0x35, 0xb9, 0x79, - 0x40, 0x75, 0xf6, 0x2d, 0x47, 0x29, 0x58, 0xa2, 0x15, 0x28, 0x5f, 0xa4, 0x50, 0xf9, 0x72, 0x19, - 0x24, 0xfa, 0xf6, 0x8e, 0xa5, 0xf5, 0x31, 0x0b, 0xf5, 0x92, 0xe2, 0x0b, 0xe4, 0x87, 0x80, 0xe6, - 0x93, 0x0d, 0xea, 0x40, 0x0e, 0x1f, 0x63, 0x83, 0xf0, 0x5a, 0xae, 0xb8, 0x7d, 0x71, 0x41, 0x71, - 0x85, 0x0d, 0xd2, 0xac, 0xd1, 0x45, 0xfe, 0xe7, 0xd7, 0x1b, 0x55, 0xae, 0xfd, 0x82, 0x39, 0xd1, - 0x09, 0x9e, 0x58, 0xe4, 0x54, 0x11, 0xf6, 0xf2, 0xdf, 0x52, 0x14, 0x10, 0x84, 0x12, 0xd1, 0xc2, - 0xb5, 0x75, 0x0f, 0x50, 0x2a, 0x00, 0x04, 0xe3, 0xad, 0xf7, 0x3a, 0xc0, 0x50, 0x73, 0xd4, 0x4f, - 0x34, 0x83, 0xe0, 0x81, 0x58, 0xf4, 0x80, 0x04, 0xd5, 0xa1, 0x40, 0x7b, 0x53, 0x07, 0x0f, 0x04, - 0x26, 0xf5, 0xfa, 0x81, 0x79, 0xe6, 0xbf, 0xdf, 0x3c, 0xc3, 0xab, 0x5c, 0x98, 0x59, 0xe5, 0x40, - 0xb1, 0x2e, 0x05, 0x8b, 0x75, 0xfa, 0x6e, 0x96, 0xad, 0x9b, 0xb6, 0x4e, 0x4e, 0xd9, 0xa7, 0x49, - 0x2b, 0x5e, 0x1f, 0x5d, 0x83, 0xd2, 0x04, 0x4f, 0x2c, 0xd3, 0x1c, 0xab, 0x3c, 0x78, 0x15, 0x99, - 0xe9, 0x8a, 0x10, 0xb6, 0x59, 0x0c, 0xfb, 0x34, 0xe5, 0x1f, 0x3f, 0x1f, 0x94, 0xfd, 0xdf, 0x2d, - 0xb0, 0xfc, 0x6b, 0xc6, 0xd2, 0x84, 0x4b, 0x0d, 0x74, 0x08, 0xab, 0xde, 0xf1, 0x57, 0xa7, 0x2c, - 0x2c, 0xb8, 0x1b, 0x3a, 0x6e, 0xfc, 0xa8, 0x1e, 0x87, 0xc5, 0x0e, 0xfa, 0x09, 0x5c, 0x9a, 0x09, - 0x6d, 0x9e, 0xeb, 0x54, 0xcc, 0x08, 0xf7, 0x44, 0x38, 0xc2, 0xb9, 0x9e, 0xfd, 0xb5, 0x4a, 0x7f, - 0xcf, 0x43, 0xb7, 0x43, 0xc1, 0x7f, 0xb0, 0x70, 0x5a, 0xf8, 0xf5, 0xaf, 0x41, 0xc9, 0xc6, 0x44, - 0xd3, 0x0d, 0x35, 0x44, 0xad, 0xac, 0x70, 0xa1, 0x20, 0x6c, 0x0e, 0xe0, 0x89, 0x85, 0x05, 0x14, - 0x7a, 0x0d, 0x24, 0xbf, 0xf6, 0x4a, 0x46, 0x40, 0x30, 0x0f, 0x7d, 0xfb, 0xba, 0xf2, 0x1f, 0x93, - 0xbe, 0xcb, 0x30, 0x9e, 0x6f, 0x43, 0xce, 0xc6, 0xce, 0x74, 0xcc, 0x11, 0x76, 0x79, 0xfb, 0xc5, - 0x78, 0xa5, 0x17, 0x95, 0x4e, 0xc7, 0x44, 0x11, 0xc6, 0xf2, 0x43, 0xc8, 0x71, 0x09, 0x2a, 0x42, - 0xfe, 0xfe, 0xde, 0xbd, 0xbd, 0xfd, 0xf7, 0xf7, 0xaa, 0x09, 0x04, 0x90, 0x6b, 0xb4, 0x5a, 0xed, - 0x83, 0x6e, 0x35, 0x89, 0x24, 0xc8, 0x36, 0x9a, 0xfb, 0x4a, 0xb7, 0x9a, 0xa2, 0x62, 0xa5, 0xfd, - 0x6e, 0xbb, 0xd5, 0xad, 0xa6, 0xd1, 0x2a, 0x94, 0x78, 0x5b, 0xbd, 0xbb, 0xaf, 0xbc, 0xd7, 0xe8, - 0x56, 0x33, 0x01, 0xd1, 0x61, 0x7b, 0xef, 0x4e, 0x5b, 0xa9, 0x66, 0xe5, 0x97, 0x29, 0x84, 0x8f, - 0x28, 0xd6, 0x7c, 0xb0, 0x9e, 0x0c, 0x80, 0x75, 0xf9, 0xb7, 0x29, 0xa8, 0x47, 0x57, 0x60, 0xe8, - 0xdd, 0x99, 0x89, 0x6f, 0x9f, 0xa3, 0x7c, 0x9b, 0x99, 0x3d, 0x7a, 0x06, 0xca, 0x36, 0x3e, 0xc2, - 0xa4, 0x3f, 0xe2, 0x15, 0x21, 0xcf, 0x98, 0x25, 0xa5, 0x24, 0xa4, 0xcc, 0xc8, 0xe1, 0x6a, 0x1f, - 0xe1, 0x3e, 0x51, 0x79, 0x28, 0xe2, 0x9b, 0x4e, 0xa2, 0x6a, 0x54, 0x7a, 0xc8, 0x85, 0xf2, 0x87, - 0xe7, 0x5a, 0x4b, 0x09, 0xb2, 0x4a, 0xbb, 0xab, 0x7c, 0x50, 0x4d, 0x23, 0x04, 0x65, 0xd6, 0x54, - 0x0f, 0xf7, 0x1a, 0x07, 0x87, 0x9d, 0x7d, 0xba, 0x96, 0x17, 0xa0, 0xe2, 0xae, 0xa5, 0x2b, 0xcc, - 0xca, 0xb7, 0xe1, 0x52, 0x44, 0xf9, 0xb8, 0x84, 0xb0, 0x90, 0x7f, 0x97, 0x0c, 0x9a, 0x86, 0x99, - 0x88, 0x7d, 0xc8, 0x39, 0x44, 0x23, 0x53, 0x47, 0xac, 0xe8, 0x6b, 0x71, 0x8b, 0xcb, 0x4d, 0xb7, - 0x71, 0xc8, 0xcc, 0x15, 0xe1, 0x46, 0xbe, 0x05, 0xe5, 0xf0, 0x48, 0xf4, 0x82, 0xf8, 0x3b, 0x2a, - 0x25, 0xff, 0x27, 0x09, 0x95, 0x99, 0xe3, 0x8f, 0xb6, 0x21, 0xcb, 0x31, 0x53, 0xd4, 0xaf, 0x3e, - 0x16, 0xbd, 0x44, 0xac, 0xe0, 0xaa, 0xe8, 0x4d, 0x28, 0x60, 0x41, 0x67, 0x2c, 0x0a, 0x33, 0x9c, - 0xa9, 0x74, 0x09, 0x0f, 0x61, 0xea, 0x59, 0xa0, 0xb7, 0x40, 0xf2, 0xe2, 0x98, 0x00, 0xea, 0x4f, - 0xcf, 0x9b, 0x7b, 0x11, 0x50, 0xd8, 0xfb, 0x36, 0xe8, 0x75, 0xbf, 0x94, 0xcd, 0xcc, 0x23, 0x35, - 0x61, 0xce, 0x15, 0x84, 0xb1, 0xab, 0x2f, 0xb7, 0xa0, 0x18, 0x98, 0x0f, 0x7a, 0x0a, 0xa4, 0x89, - 0x76, 0x22, 0x98, 0x64, 0xce, 0x07, 0x16, 0x26, 0xda, 0x09, 0x27, 0x91, 0x2f, 0x41, 0x9e, 0x0e, - 0x0e, 0x35, 0x47, 0x50, 0x4f, 0xb9, 0x89, 0x76, 0xf2, 0x8e, 0xe6, 0xc8, 0x1f, 0x00, 0x04, 0xf8, - 0xd2, 0x35, 0xc8, 0xda, 0xe6, 0xd4, 0x18, 0x30, 0xfb, 0xac, 0xc2, 0x3b, 0xe8, 0x16, 0x64, 0x8f, - 0x4d, 0x1e, 0x86, 0x17, 0x07, 0xa3, 0x07, 0x26, 0xc1, 0x01, 0x66, 0x89, 0x6b, 0xcb, 0x8f, 0x21, - 0xcb, 0xc2, 0x2a, 0x0d, 0x91, 0x8c, 0x0f, 0x15, 0x25, 0x3c, 0x6d, 0xa3, 0x5f, 0x00, 0x68, 0x84, - 0xd8, 0x7a, 0x6f, 0xea, 0x3b, 0xde, 0x58, 0x1c, 0x96, 0x1b, 0xae, 0x5e, 0xf3, 0xb2, 0x88, 0xcf, - 0x6b, 0xbe, 0x69, 0x20, 0x46, 0x07, 0x1c, 0xca, 0x7b, 0x50, 0x0e, 0xdb, 0x06, 0xff, 0x4a, 0xac, - 0x2c, 0xf8, 0x2b, 0xe1, 0x95, 0x89, 0x5e, 0x91, 0x99, 0xe6, 0xbc, 0x37, 0xeb, 0xc8, 0x9f, 0x25, - 0xa1, 0xd0, 0x3d, 0x11, 0x07, 0x36, 0x82, 0x76, 0xf5, 0x4d, 0x53, 0x41, 0x92, 0x91, 0xf3, 0xb8, - 0x69, 0x8f, 0x1d, 0x7e, 0xdb, 0x0b, 0x49, 0x99, 0xb8, 0xec, 0x80, 0x4b, 0x91, 0x8b, 0x30, 0xfc, - 0x06, 0x48, 0xde, 0x8e, 0xa2, 0x58, 0xc8, 0xa5, 0xb3, 0x92, 0xa2, 0xf4, 0xe6, 0x5d, 0xc6, 0xe0, - 0x9b, 0x9f, 0x08, 0x1a, 0x33, 0xad, 0xf0, 0x8e, 0x3c, 0x80, 0xca, 0x4c, 0x42, 0x46, 0x6f, 0x40, - 0xde, 0x9a, 0xf6, 0x54, 0x77, 0x79, 0x66, 0x0e, 0x8e, 0x5b, 0x17, 0x4f, 0x7b, 0x63, 0xbd, 0x7f, - 0x0f, 0x9f, 0xba, 0x2f, 0x63, 0x4d, 0x7b, 0xf7, 0xf8, 0x2a, 0xf2, 0xa7, 0xa4, 0x82, 0x4f, 0x39, - 0x86, 0x82, 0xbb, 0x29, 0xd0, 0x8f, 0x82, 0x67, 0xc4, 0xfd, 0xaf, 0x13, 0x59, 0x24, 0x08, 0xf7, - 0x81, 0x23, 0x72, 0x13, 0x56, 0x1d, 0x7d, 0x68, 0xb8, 0x3c, 0x27, 0x3f, 0xe1, 0x29, 0xf6, 0x75, - 0x2a, 0x7c, 0x60, 0xd7, 0x85, 0x62, 0xf2, 0xbf, 0x93, 0x50, 0x70, 0x0f, 0x2b, 0x7a, 0x39, 0xb0, - 0xef, 0xca, 0x0b, 0x98, 0x30, 0x57, 0xd1, 0x27, 0xe2, 0xc3, 0xef, 0x9a, 0x3a, 0xff, 0xbb, 0x46, - 0xfd, 0x4d, 0x71, 0x99, 0xce, 0xcc, 0xb9, 0x99, 0xce, 0x17, 0x00, 0x11, 0x93, 0x68, 0x63, 0xf5, - 0xd8, 0x24, 0xba, 0x31, 0x54, 0xf9, 0x62, 0xf3, 0x5a, 0xb1, 0xca, 0x46, 0x1e, 0xb0, 0x81, 0x03, - 0xb6, 0xee, 0xbf, 0x4a, 0x42, 0xc1, 0xcb, 0xfa, 0xe7, 0xe5, 0xd5, 0x2f, 0x42, 0x4e, 0x24, 0x36, - 0x4e, 0xac, 0x8b, 0xde, 0x42, 0x4a, 0xb7, 0x0e, 0x85, 0x09, 0x26, 0x1a, 0xcb, 0x1f, 0x1c, 0x10, - 0x7b, 0xfd, 0x9b, 0xaf, 0x43, 0x31, 0xf0, 0x8b, 0x83, 0x9e, 0xbc, 0xbd, 0xf6, 0xfb, 0xd5, 0x44, - 0x3d, 0xff, 0xd9, 0x17, 0x57, 0xd3, 0x7b, 0xf8, 0x13, 0xba, 0x67, 0x95, 0x76, 0xab, 0xd3, 0x6e, - 0xdd, 0xab, 0x26, 0xeb, 0xc5, 0xcf, 0xbe, 0xb8, 0x9a, 0x57, 0x30, 0x23, 0xd0, 0x6e, 0x76, 0x60, - 0x25, 0xf8, 0x55, 0xc2, 0xa9, 0x00, 0x41, 0xf9, 0xce, 0xfd, 0x83, 0xdd, 0x9d, 0x56, 0xa3, 0xdb, - 0x56, 0x1f, 0xec, 0x77, 0xdb, 0xd5, 0x24, 0xba, 0x04, 0x17, 0x76, 0x77, 0xde, 0xe9, 0x74, 0xd5, - 0xd6, 0xee, 0x4e, 0x7b, 0xaf, 0xab, 0x36, 0xba, 0xdd, 0x46, 0xeb, 0x5e, 0x35, 0xb5, 0xfd, 0x97, - 0x22, 0x54, 0x1a, 0xcd, 0xd6, 0x0e, 0xcd, 0xeb, 0x7a, 0x5f, 0x13, 0x04, 0x65, 0x86, 0xf1, 0x11, - 0x67, 0xde, 0x01, 0xa9, 0x9f, 0xcd, 0xcf, 0xa2, 0xbb, 0x90, 0x65, 0x54, 0x05, 0x3a, 0xfb, 0x52, - 0x48, 0x7d, 0x09, 0x61, 0x4b, 0x5f, 0x86, 0x1d, 0x8f, 0x33, 0x6f, 0x89, 0xd4, 0xcf, 0xe6, 0x6f, - 0x91, 0x02, 0x92, 0xcf, 0x35, 0x2c, 0xbf, 0x35, 0x52, 0x8f, 0xc1, 0xe9, 0x52, 0x9f, 0x3e, 0xe0, - 0x59, 0x7e, 0x8b, 0xa2, 0x1e, 0x23, 0x80, 0xa1, 0x5d, 0xc8, 0xbb, 0x18, 0x75, 0xd9, 0xbd, 0x8e, - 0xfa, 0x52, 0xbe, 0x95, 0x7e, 0x02, 0xce, 0x25, 0x9c, 0x7d, 0x49, 0xa5, 0xbe, 0x84, 0x3c, 0x46, - 0x3b, 0x90, 0x13, 0x55, 0xfc, 0x92, 0xbb, 0x1a, 0xf5, 0x65, 0xfc, 0x29, 0x5d, 0x34, 0x9f, 0xa4, - 0x59, 0x7e, 0xf5, 0xa6, 0x1e, 0x83, 0x17, 0x47, 0xf7, 0x01, 0x02, 0xcc, 0x41, 0x8c, 0x3b, 0x35, - 0xf5, 0x38, 0x7c, 0x37, 0xda, 0x87, 0x82, 0x07, 0xe4, 0x96, 0xde, 0x70, 0xa9, 0x2f, 0x27, 0x9e, - 0xd1, 0x43, 0x28, 0x85, 0x11, 0x4c, 0xbc, 0x7b, 0x2b, 0xf5, 0x98, 0x8c, 0x32, 0xf5, 0x1f, 0x86, - 0x33, 0xf1, 0xee, 0xb1, 0xd4, 0x63, 0x12, 0xcc, 0xe8, 0x23, 0x58, 0x9d, 0x87, 0x1b, 0xf1, 0xaf, - 0xb5, 0xd4, 0xcf, 0x41, 0x39, 0xa3, 0x09, 0xa0, 0x05, 0x30, 0xe5, 0x1c, 0xb7, 0x5c, 0xea, 0xe7, - 0x61, 0xa0, 0xd1, 0x00, 0x2a, 0xb3, 0xb5, 0x7f, 0xdc, 0x5b, 0x2f, 0xf5, 0xd8, 0x6c, 0x34, 0x7f, - 0x4a, 0x18, 0x26, 0xc4, 0xbd, 0x05, 0x53, 0x8f, 0x4d, 0x4e, 0x37, 0xdb, 0x5f, 0x7e, 0xb3, 0x9e, - 0xfc, 0xea, 0x9b, 0xf5, 0xe4, 0x3f, 0xbe, 0x59, 0x4f, 0x7e, 0xfe, 0xed, 0x7a, 0xe2, 0xab, 0x6f, - 0xd7, 0x13, 0x7f, 0xfd, 0x76, 0x3d, 0xf1, 0xd3, 0xe7, 0x87, 0x3a, 0x19, 0x4d, 0x7b, 0x9b, 0x7d, - 0x73, 0xb2, 0x15, 0xbc, 0x4e, 0xb8, 0xe8, 0x8a, 0x63, 0x2f, 0xc7, 0x92, 0xee, 0x2b, 0xff, 0x0d, - 0x00, 0x00, 0xff, 0xff, 0xe7, 0x68, 0x0b, 0x00, 0x02, 0x29, 0x00, 0x00, + // 3078 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0xcb, 0x77, 0x23, 0xc5, + 0xd5, 0xd7, 0xfb, 0x71, 0x6d, 0x49, 0xed, 0x9a, 0x61, 0x46, 0x88, 0xc1, 0x1e, 0x7a, 0x0e, 0x30, + 0x0c, 0xe0, 0xf9, 0x30, 0x07, 0xbe, 0xe1, 0xf5, 0x81, 0x2d, 0x6b, 0x90, 0xe7, 0x61, 0xf9, 0x2b, + 0xcb, 0xc3, 0xf7, 0x25, 0x61, 0x9a, 0xb6, 0xba, 0x6c, 0x35, 0x23, 0x75, 0x37, 0xdd, 0x25, 0x23, + 0xb3, 0xcc, 0x49, 0x36, 0x64, 0xc3, 0x2e, 0xd9, 0xb0, 0xcc, 0xff, 0x90, 0x45, 0x4e, 0x36, 0x6c, + 0x38, 0x27, 0x1b, 0x96, 0x59, 0xe4, 0x90, 0x1c, 0x58, 0xe4, 0x24, 0xff, 0x40, 0x56, 0x39, 0xc9, + 0xa9, 0x47, 0xbf, 0x24, 0xb5, 0x25, 0x03, 0x27, 0x9b, 0xec, 0xaa, 0x6e, 0xdd, 0x7b, 0xab, 0xeb, + 0xf5, 0xab, 0xdf, 0xbd, 0x5d, 0xf0, 0x04, 0x25, 0x96, 0x41, 0xdc, 0xa1, 0x69, 0xd1, 0x9b, 0xfa, + 0x61, 0xcf, 0xbc, 0x49, 0x4f, 0x1d, 0xe2, 0xad, 0x3b, 0xae, 0x4d, 0x6d, 0x54, 0x0b, 0x1b, 0xd7, + 0x59, 0x63, 0xe3, 0xc9, 0x88, 0x76, 0xcf, 0x3d, 0x75, 0xa8, 0x7d, 0xd3, 0x71, 0x6d, 0xfb, 0x48, + 0xe8, 0x37, 0xae, 0x44, 0x9a, 0xb9, 0x9f, 0xa8, 0xb7, 0x58, 0xab, 0x34, 0x7e, 0x44, 0x4e, 0xfd, + 0xd6, 0x27, 0xa7, 0x6c, 0x1d, 0xdd, 0xd5, 0x87, 0x7e, 0xf3, 0xda, 0xb1, 0x6d, 0x1f, 0x0f, 0xc8, + 0x4d, 0x5e, 0x3b, 0x1c, 0x1d, 0xdd, 0xa4, 0xe6, 0x90, 0x78, 0x54, 0x1f, 0x3a, 0x52, 0xe1, 0xe2, + 0xb1, 0x7d, 0x6c, 0xf3, 0xe2, 0x4d, 0x56, 0x12, 0x52, 0xf5, 0x2f, 0x25, 0x28, 0x62, 0xf2, 0xd1, + 0x88, 0x78, 0x14, 0x6d, 0x40, 0x8e, 0xf4, 0xfa, 0x76, 0x3d, 0x7d, 0x35, 0x7d, 0x7d, 0x69, 0xe3, + 0xca, 0xfa, 0xc4, 0xe0, 0xd6, 0xa5, 0x5e, 0xab, 0xd7, 0xb7, 0xdb, 0x29, 0xcc, 0x75, 0xd1, 0x2b, + 0x90, 0x3f, 0x1a, 0x8c, 0xbc, 0x7e, 0x3d, 0xc3, 0x8d, 0x9e, 0x4c, 0x32, 0xba, 0xcd, 0x94, 0xda, + 0x29, 0x2c, 0xb4, 0x59, 0x57, 0xa6, 0x75, 0x64, 0xd7, 0xb3, 0x67, 0x77, 0xb5, 0x63, 0x1d, 0xf1, + 0xae, 0x98, 0x2e, 0xda, 0x02, 0xf0, 0x08, 0xd5, 0x6c, 0x87, 0x9a, 0xb6, 0x55, 0xcf, 0x71, 0xcb, + 0xa7, 0x92, 0x2c, 0xf7, 0x09, 0xed, 0x70, 0xc5, 0x76, 0x0a, 0x97, 0x3d, 0xbf, 0xc2, 0x7c, 0x98, + 0x96, 0x49, 0xb5, 0x5e, 0x5f, 0x37, 0xad, 0x7a, 0xfe, 0x6c, 0x1f, 0x3b, 0x96, 0x49, 0x9b, 0x4c, + 0x91, 0xf9, 0x30, 0xfd, 0x0a, 0x1b, 0xf2, 0x47, 0x23, 0xe2, 0x9e, 0xd6, 0x0b, 0x67, 0x0f, 0xf9, + 0x7f, 0x99, 0x12, 0x1b, 0x32, 0xd7, 0x46, 0x2d, 0x58, 0x3a, 0x24, 0xc7, 0xa6, 0xa5, 0x1d, 0x0e, + 0xec, 0xde, 0xa3, 0x7a, 0x91, 0x1b, 0xab, 0x49, 0xc6, 0x5b, 0x4c, 0x75, 0x8b, 0x69, 0xb6, 0x53, + 0x18, 0x0e, 0x83, 0x1a, 0x7a, 0x13, 0x4a, 0xbd, 0x3e, 0xe9, 0x3d, 0xd2, 0xe8, 0xb8, 0x5e, 0xe2, + 0x3e, 0xd6, 0x92, 0x7c, 0x34, 0x99, 0x5e, 0x77, 0xdc, 0x4e, 0xe1, 0x62, 0x4f, 0x14, 0xd9, 0xf8, + 0x0d, 0x32, 0x30, 0x4f, 0x88, 0xcb, 0xec, 0xcb, 0x67, 0x8f, 0x7f, 0x5b, 0x68, 0x72, 0x0f, 0x65, + 0xc3, 0xaf, 0xa0, 0xb7, 0xa1, 0x4c, 0x2c, 0x43, 0x0e, 0x03, 0xb8, 0x8b, 0xab, 0x89, 0x7b, 0xc5, + 0x32, 0xfc, 0x41, 0x94, 0x88, 0x2c, 0xa3, 0x5b, 0x50, 0xe8, 0xd9, 0xc3, 0xa1, 0x49, 0xeb, 0x4b, + 0xdc, 0x7a, 0x35, 0x71, 0x00, 0x5c, 0xab, 0x9d, 0xc2, 0x52, 0x1f, 0xed, 0x42, 0x75, 0x60, 0x7a, + 0x54, 0xf3, 0x2c, 0xdd, 0xf1, 0xfa, 0x36, 0xf5, 0xea, 0xcb, 0xdc, 0xc3, 0xd3, 0x49, 0x1e, 0xee, + 0x99, 0x1e, 0xdd, 0xf7, 0x95, 0xdb, 0x29, 0x5c, 0x19, 0x44, 0x05, 0xcc, 0x9f, 0x7d, 0x74, 0x44, + 0xdc, 0xc0, 0x61, 0xbd, 0x72, 0xb6, 0xbf, 0x0e, 0xd3, 0xf6, 0xed, 0x99, 0x3f, 0x3b, 0x2a, 0x40, + 0x3f, 0x86, 0x0b, 0x03, 0x5b, 0x37, 0x02, 0x77, 0x5a, 0xaf, 0x3f, 0xb2, 0x1e, 0xd5, 0xab, 0xdc, + 0xe9, 0x73, 0x89, 0x1f, 0x69, 0xeb, 0x86, 0xef, 0xa2, 0xc9, 0x0c, 0xda, 0x29, 0xbc, 0x32, 0x98, + 0x14, 0xa2, 0x87, 0x70, 0x51, 0x77, 0x9c, 0xc1, 0xe9, 0xa4, 0xf7, 0x1a, 0xf7, 0x7e, 0x23, 0xc9, + 0xfb, 0x26, 0xb3, 0x99, 0x74, 0x8f, 0xf4, 0x29, 0x29, 0xea, 0x82, 0xe2, 0xb8, 0xc4, 0xd1, 0x5d, + 0xa2, 0x39, 0xae, 0xed, 0xd8, 0x9e, 0x3e, 0xa8, 0x2b, 0xdc, 0xf7, 0xb3, 0x49, 0xbe, 0xf7, 0x84, + 0xfe, 0x9e, 0x54, 0x6f, 0xa7, 0x70, 0xcd, 0x89, 0x8b, 0xb6, 0x8a, 0x90, 0x3f, 0xd1, 0x07, 0x23, + 0xa2, 0x3e, 0x0b, 0x4b, 0x11, 0x00, 0x41, 0x75, 0x28, 0x0e, 0x89, 0xe7, 0xe9, 0xc7, 0x84, 0xe3, + 0x4d, 0x19, 0xfb, 0x55, 0xb5, 0x0a, 0xcb, 0x51, 0xd0, 0x50, 0x87, 0x81, 0x21, 0x83, 0x03, 0x66, + 0x78, 0x42, 0x5c, 0x8f, 0x61, 0x80, 0x34, 0x94, 0x55, 0x74, 0x0d, 0x2a, 0x7c, 0x53, 0x6a, 0x7e, + 0x3b, 0xc3, 0xa4, 0x1c, 0x5e, 0xe6, 0xc2, 0x07, 0x52, 0x69, 0x0d, 0x96, 0x9c, 0x0d, 0x27, 0x50, + 0xc9, 0x72, 0x15, 0x70, 0x36, 0x1c, 0xa9, 0xa0, 0xbe, 0x0e, 0xca, 0x24, 0x86, 0x20, 0x05, 0xb2, + 0x8f, 0xc8, 0xa9, 0xec, 0x8f, 0x15, 0xd1, 0x45, 0x39, 0x2c, 0xde, 0x47, 0x19, 0xcb, 0x31, 0xfe, + 0x3e, 0x13, 0x18, 0x07, 0xe0, 0x81, 0x6e, 0x41, 0x8e, 0x61, 0xb1, 0x84, 0xd5, 0xc6, 0xba, 0x00, + 0xea, 0x75, 0x1f, 0xa8, 0xd7, 0xbb, 0x3e, 0x50, 0x6f, 0x95, 0xbe, 0xfc, 0x7a, 0x2d, 0xf5, 0xd9, + 0x9f, 0xd6, 0xd2, 0x98, 0x5b, 0xa0, 0xc7, 0xd9, 0x59, 0xd7, 0x4d, 0x4b, 0x33, 0x0d, 0xd9, 0x4f, + 0x91, 0xd7, 0x77, 0x0c, 0x74, 0x17, 0x94, 0x9e, 0x6d, 0x79, 0xc4, 0xf2, 0x46, 0x9e, 0x26, 0x2e, + 0x02, 0x09, 0xa6, 0xd3, 0x67, 0xb1, 0xe9, 0x2b, 0xee, 0x71, 0x3d, 0x5c, 0xeb, 0xc5, 0x05, 0xe8, + 0x36, 0xc0, 0x89, 0x3e, 0x30, 0x0d, 0x9d, 0xda, 0xae, 0x57, 0xcf, 0x5d, 0xcd, 0xce, 0x74, 0xf3, + 0xc0, 0x57, 0x39, 0x70, 0x0c, 0x9d, 0x92, 0xad, 0x1c, 0xfb, 0x5a, 0x1c, 0xb1, 0x44, 0xcf, 0x40, + 0x4d, 0x77, 0x1c, 0xcd, 0xa3, 0x3a, 0x25, 0xda, 0xe1, 0x29, 0x25, 0x1e, 0x87, 0xd8, 0x65, 0x5c, + 0xd1, 0x1d, 0x67, 0x9f, 0x49, 0xb7, 0x98, 0x10, 0x3d, 0x0d, 0x55, 0x06, 0xa7, 0xa6, 0x3e, 0xd0, + 0xfa, 0xc4, 0x3c, 0xee, 0x53, 0x0e, 0xa5, 0x59, 0x5c, 0x91, 0xd2, 0x36, 0x17, 0xaa, 0x46, 0xb0, + 0x11, 0x38, 0x94, 0x22, 0x04, 0x39, 0x43, 0xa7, 0x3a, 0x9f, 0xc8, 0x65, 0xcc, 0xcb, 0x4c, 0xe6, + 0xe8, 0xb4, 0x2f, 0xa7, 0x87, 0x97, 0xd1, 0x25, 0x28, 0x48, 0xb7, 0x59, 0xee, 0x56, 0xd6, 0xd8, + 0x9a, 0x39, 0xae, 0x7d, 0x42, 0xf8, 0xdd, 0x51, 0xc2, 0xa2, 0xa2, 0xfe, 0x2c, 0x03, 0x2b, 0x53, + 0xa0, 0xcb, 0xfc, 0xf6, 0x75, 0xaf, 0xef, 0xf7, 0xc5, 0xca, 0xe8, 0x55, 0xe6, 0x57, 0x37, 0x88, + 0x2b, 0x2f, 0xbb, 0x7a, 0x74, 0x8a, 0xc4, 0x45, 0xde, 0xe6, 0xed, 0x72, 0x6a, 0xa4, 0x36, 0xea, + 0x80, 0x32, 0xd0, 0x3d, 0xaa, 0x09, 0x10, 0xd3, 0x22, 0x17, 0xdf, 0x34, 0x74, 0xdf, 0xd3, 0x7d, + 0xd8, 0x63, 0x9b, 0x5d, 0x3a, 0xaa, 0x0e, 0x62, 0x52, 0x84, 0xe1, 0xe2, 0xe1, 0xe9, 0x27, 0xba, + 0x45, 0x4d, 0x8b, 0x68, 0x53, 0x2b, 0xf7, 0xf8, 0x94, 0xd3, 0xd6, 0x89, 0x69, 0x10, 0xab, 0xe7, + 0x2f, 0xd9, 0x85, 0xc0, 0x38, 0x58, 0x52, 0x4f, 0xc5, 0x50, 0x8d, 0x5f, 0x1b, 0xa8, 0x0a, 0x19, + 0x3a, 0x96, 0x13, 0x90, 0xa1, 0x63, 0xf4, 0x5f, 0x90, 0x63, 0x83, 0xe4, 0x83, 0xaf, 0xce, 0xb8, + 0xb3, 0xa5, 0x5d, 0xf7, 0xd4, 0x21, 0x98, 0x6b, 0xaa, 0x6a, 0x70, 0x1a, 0x82, 0xab, 0x64, 0xd2, + 0xab, 0xfa, 0x1c, 0xd4, 0x26, 0xee, 0x8a, 0xc8, 0xfa, 0xa5, 0xa3, 0xeb, 0xa7, 0xd6, 0xa0, 0x12, + 0xbb, 0x18, 0xd4, 0x4b, 0x70, 0x71, 0x16, 0xce, 0xab, 0xfd, 0x40, 0x1e, 0xc3, 0x6b, 0xf4, 0x0a, + 0x94, 0x02, 0xa0, 0x17, 0xa7, 0x71, 0x7a, 0xae, 0x7c, 0x65, 0x1c, 0xa8, 0xb2, 0x63, 0xc8, 0xb6, + 0x35, 0xdf, 0x0f, 0x19, 0xfe, 0xe1, 0x45, 0xdd, 0x71, 0xda, 0xba, 0xd7, 0x57, 0x3f, 0x80, 0x7a, + 0x12, 0x88, 0x4f, 0x0c, 0x23, 0x17, 0x6c, 0xc3, 0x4b, 0x50, 0x38, 0xb2, 0xdd, 0xa1, 0x4e, 0xb9, + 0xb3, 0x0a, 0x96, 0x35, 0xb6, 0x3d, 0x05, 0xa0, 0x67, 0xb9, 0x58, 0x54, 0x54, 0x0d, 0x1e, 0x4f, + 0x04, 0x72, 0x66, 0x62, 0x5a, 0x06, 0x11, 0xf3, 0x59, 0xc1, 0xa2, 0x12, 0x3a, 0x12, 0x1f, 0x2b, + 0x2a, 0xac, 0x5b, 0x8f, 0x8f, 0x95, 0xfb, 0x2f, 0x63, 0x59, 0x53, 0xbf, 0xc8, 0xc0, 0xa5, 0xd9, + 0x70, 0xfe, 0x83, 0x1e, 0x02, 0x05, 0xb2, 0x74, 0xcc, 0x30, 0x2a, 0x7b, 0x7d, 0x19, 0xb3, 0x22, + 0x3a, 0x80, 0x95, 0x81, 0xdd, 0xd3, 0x07, 0x5a, 0xe4, 0x70, 0x48, 0x5a, 0x77, 0x6d, 0x7a, 0x0b, + 0x8f, 0xb9, 0xc4, 0x98, 0x3a, 0x1b, 0x35, 0xee, 0x23, 0x3c, 0x36, 0x89, 0x87, 0x23, 0xff, 0xdd, + 0x0f, 0x07, 0xba, 0x0a, 0xcb, 0x43, 0x7d, 0xac, 0xd1, 0xb1, 0x44, 0x35, 0x01, 0x57, 0x30, 0xd4, + 0xc7, 0xdd, 0x31, 0x87, 0x34, 0xf5, 0xb7, 0x65, 0x28, 0x61, 0xe2, 0x39, 0x0c, 0x59, 0xd1, 0x16, + 0x94, 0xc9, 0xb8, 0x47, 0x04, 0x51, 0x4d, 0x27, 0x12, 0x3d, 0xa1, 0xdd, 0xf2, 0x35, 0x19, 0xcb, + 0x0a, 0xcc, 0xd0, 0xcb, 0x92, 0x8c, 0x27, 0xf3, 0x6a, 0x69, 0x1e, 0x65, 0xe3, 0xaf, 0xfa, 0x6c, + 0x3c, 0x9b, 0x48, 0xac, 0x84, 0xd5, 0x04, 0x1d, 0x7f, 0x59, 0xd2, 0xf1, 0xdc, 0x9c, 0xce, 0x62, + 0x7c, 0xbc, 0x19, 0xe3, 0xe3, 0xf9, 0x39, 0xc3, 0x4c, 0x20, 0xe4, 0xcd, 0x18, 0x21, 0x2f, 0xcc, + 0x71, 0x92, 0xc0, 0xc8, 0x5f, 0xf5, 0x19, 0x79, 0x71, 0xce, 0xb0, 0x27, 0x28, 0xf9, 0xed, 0x38, + 0x25, 0x2f, 0x25, 0xec, 0x3d, 0xdf, 0x3a, 0x91, 0x93, 0xbf, 0x15, 0xe1, 0xe4, 0xe5, 0x44, 0x42, + 0x2c, 0x9c, 0xcc, 0x20, 0xe5, 0xcd, 0x18, 0x29, 0x87, 0x39, 0x73, 0x90, 0xc0, 0xca, 0xdf, 0x89, + 0xb2, 0xf2, 0xa5, 0x44, 0x62, 0x2f, 0x37, 0xcd, 0x2c, 0x5a, 0xfe, 0x5a, 0x40, 0xcb, 0x97, 0x13, + 0xe3, 0x0a, 0x39, 0x86, 0x49, 0x5e, 0xde, 0x99, 0xe2, 0xe5, 0x82, 0x47, 0x3f, 0x93, 0xe8, 0x62, + 0x0e, 0x31, 0xef, 0x4c, 0x11, 0xf3, 0xea, 0x1c, 0x87, 0x73, 0x98, 0xf9, 0x4f, 0x66, 0x33, 0xf3, + 0x64, 0xee, 0x2c, 0x3f, 0x73, 0x31, 0x6a, 0xae, 0x25, 0x50, 0x73, 0x41, 0x9f, 0x9f, 0x4f, 0x74, + 0xbf, 0x30, 0x37, 0x3f, 0x98, 0xc1, 0xcd, 0x57, 0xb8, 0xf3, 0xeb, 0x89, 0xce, 0xcf, 0x43, 0xce, + 0x9f, 0x63, 0x1c, 0x68, 0x02, 0x8f, 0xd8, 0x3d, 0x42, 0x5c, 0xd7, 0x76, 0x25, 0xef, 0x15, 0x15, + 0xf5, 0x3a, 0x63, 0x65, 0x21, 0xf6, 0x9c, 0x41, 0xe4, 0xf9, 0x7d, 0x1d, 0xc1, 0x1b, 0xf5, 0x37, + 0xe9, 0xd0, 0x96, 0x13, 0x99, 0x28, 0xa3, 0x2b, 0x4b, 0x46, 0x17, 0xe1, 0xf7, 0x99, 0x38, 0xbf, + 0x5f, 0x83, 0x25, 0x76, 0x0f, 0x4f, 0x50, 0x77, 0xdd, 0xf1, 0xa9, 0x3b, 0xba, 0x01, 0x2b, 0xfc, + 0x2e, 0x11, 0x51, 0x80, 0xbc, 0x7c, 0x73, 0x1c, 0xab, 0x6b, 0xac, 0x41, 0xec, 0x79, 0x71, 0x0b, + 0xbf, 0x08, 0x17, 0x22, 0xba, 0xc1, 0xfd, 0x2e, 0xf8, 0xaa, 0x12, 0x68, 0x6f, 0xca, 0x8b, 0xfe, + 0x7e, 0x38, 0x41, 0x61, 0x58, 0x80, 0x20, 0xd7, 0xb3, 0x0d, 0x22, 0x6f, 0x5f, 0x5e, 0x66, 0xf7, + 0xdc, 0xc0, 0x3e, 0x96, 0x77, 0x2c, 0x2b, 0x32, 0xad, 0x00, 0x5c, 0xcb, 0x02, 0x3b, 0xd5, 0x2f, + 0xd2, 0xa1, 0xbf, 0x30, 0x52, 0x98, 0x45, 0xea, 0xd3, 0x3f, 0x0c, 0xa9, 0xcf, 0x7c, 0x67, 0x52, + 0x1f, 0x65, 0x3f, 0xd9, 0x38, 0xfb, 0xf9, 0x7b, 0x3a, 0x5c, 0xe1, 0x80, 0xa2, 0x7f, 0xb7, 0x19, + 0x09, 0xa9, 0x4c, 0x9e, 0xaf, 0x97, 0xa4, 0x32, 0x32, 0xf0, 0x2a, 0xf0, 0x7e, 0xe3, 0x81, 0x57, + 0x51, 0x90, 0x1b, 0x5e, 0x41, 0xb7, 0xa0, 0xcc, 0xf3, 0x6c, 0x9a, 0xed, 0x78, 0x12, 0xc7, 0x9f, + 0x88, 0x8e, 0x55, 0xa4, 0xd3, 0xd6, 0xf7, 0x98, 0x4e, 0xc7, 0xf1, 0x70, 0xc9, 0x91, 0xa5, 0x08, + 0x4b, 0x2b, 0xc7, 0x82, 0x85, 0x2b, 0x50, 0x66, 0x5f, 0xef, 0x39, 0x7a, 0x8f, 0x70, 0x4c, 0x2e, + 0xe3, 0x50, 0xa0, 0x3e, 0x04, 0x34, 0x7d, 0x2b, 0xa0, 0x36, 0x14, 0xc8, 0x09, 0xb1, 0x28, 0x5b, + 0x35, 0x36, 0xdd, 0x97, 0x66, 0x90, 0x0d, 0x62, 0xd1, 0xad, 0x3a, 0x9b, 0xe4, 0xbf, 0x7d, 0xbd, + 0xa6, 0x08, 0xed, 0x17, 0xec, 0xa1, 0x49, 0xc9, 0xd0, 0xa1, 0xa7, 0x58, 0xda, 0xab, 0x7f, 0xcc, + 0x30, 0x5a, 0x1c, 0xbb, 0x31, 0x66, 0xce, 0xad, 0x7f, 0x80, 0x32, 0x91, 0x90, 0x68, 0xb1, 0xf9, + 0x5e, 0x05, 0x38, 0xd6, 0x3d, 0xed, 0x63, 0xdd, 0xa2, 0xc4, 0x90, 0x93, 0x1e, 0x91, 0xa0, 0x06, + 0x94, 0x58, 0x6d, 0xe4, 0x11, 0x43, 0xd2, 0x9d, 0xa0, 0x1e, 0x19, 0x67, 0xf1, 0xfb, 0x8d, 0x33, + 0x3e, 0xcb, 0xa5, 0x89, 0x59, 0x8e, 0x50, 0xd6, 0x72, 0x94, 0xb2, 0xb2, 0x6f, 0x73, 0x5c, 0xd3, + 0x76, 0x4d, 0x7a, 0xca, 0x97, 0x26, 0x8b, 0x83, 0x3a, 0xba, 0x06, 0x95, 0x21, 0x19, 0x3a, 0xb6, + 0x3d, 0xd0, 0x04, 0x78, 0x2d, 0x71, 0xd3, 0x65, 0x29, 0x6c, 0x71, 0x0c, 0xfb, 0x79, 0x26, 0x3c, + 0x7e, 0x61, 0x68, 0xf2, 0x1f, 0x37, 0xc1, 0xea, 0x2f, 0x78, 0xbe, 0x22, 0xce, 0x09, 0xd0, 0x3e, + 0xac, 0x04, 0xc7, 0x5f, 0x1b, 0x71, 0x58, 0xf0, 0x37, 0xf4, 0xa2, 0xf8, 0xa1, 0x9c, 0xc4, 0xc5, + 0x1e, 0xfa, 0x3f, 0xb8, 0x3c, 0x01, 0x6d, 0x81, 0xeb, 0xcc, 0x82, 0x08, 0xf7, 0x58, 0x1c, 0xe1, + 0x7c, 0xcf, 0xe1, 0x5c, 0x65, 0xbf, 0xe7, 0xa1, 0xdb, 0x61, 0x21, 0x70, 0x94, 0xe1, 0xcc, 0x5c, + 0xfd, 0x6b, 0x50, 0x71, 0x09, 0xd5, 0x4d, 0x4b, 0x8b, 0x25, 0x19, 0x96, 0x85, 0x50, 0xa6, 0x2e, + 0xf6, 0xe0, 0xb1, 0x99, 0x4c, 0x07, 0xfd, 0x37, 0x94, 0x43, 0x92, 0x94, 0x4e, 0x08, 0x49, 0x82, + 0x18, 0x34, 0xd4, 0x55, 0x7f, 0x97, 0x0e, 0x5d, 0xc6, 0xa3, 0xda, 0x16, 0x14, 0x5c, 0xe2, 0x8d, + 0x06, 0x22, 0xce, 0xac, 0x6e, 0xbc, 0xb8, 0x18, 0x47, 0x62, 0xd2, 0xd1, 0x80, 0x62, 0x69, 0xac, + 0x3e, 0x84, 0x82, 0x90, 0xa0, 0x25, 0x28, 0x1e, 0xec, 0xde, 0xdd, 0xed, 0xbc, 0xb7, 0xab, 0xa4, + 0x10, 0x40, 0x61, 0xb3, 0xd9, 0x6c, 0xed, 0x75, 0x95, 0x34, 0x2a, 0x43, 0x7e, 0x73, 0xab, 0x83, + 0xbb, 0x4a, 0x86, 0x89, 0x71, 0xeb, 0x4e, 0xab, 0xd9, 0x55, 0xb2, 0x68, 0x05, 0x2a, 0xa2, 0xac, + 0xdd, 0xee, 0xe0, 0xfb, 0x9b, 0x5d, 0x25, 0x17, 0x11, 0xed, 0xb7, 0x76, 0xb7, 0x5b, 0x58, 0xc9, + 0xab, 0x2f, 0xb1, 0x40, 0x36, 0x81, 0x55, 0x85, 0x21, 0x6b, 0x3a, 0x12, 0xb2, 0xaa, 0xbf, 0xca, + 0x40, 0x23, 0x99, 0x2a, 0xa1, 0x3b, 0x13, 0x03, 0xdf, 0x38, 0x07, 0xcf, 0x9a, 0x18, 0x3d, 0x7a, + 0x1a, 0xaa, 0x2e, 0x39, 0x22, 0xb4, 0xd7, 0x17, 0xd4, 0x4d, 0xdc, 0x98, 0x15, 0x5c, 0x91, 0x52, + 0x6e, 0xe4, 0x09, 0xb5, 0x0f, 0x49, 0x8f, 0x6a, 0x02, 0x8a, 0xc4, 0xa6, 0x2b, 0x33, 0x35, 0x26, + 0xdd, 0x17, 0x42, 0xf5, 0x83, 0x73, 0xcd, 0x65, 0x19, 0xf2, 0xb8, 0xd5, 0xc5, 0xff, 0xaf, 0x64, + 0x11, 0x82, 0x2a, 0x2f, 0x6a, 0xfb, 0xbb, 0x9b, 0x7b, 0xfb, 0xed, 0x0e, 0x9b, 0xcb, 0x0b, 0x50, + 0xf3, 0xe7, 0xd2, 0x17, 0xe6, 0xd5, 0x7d, 0xb8, 0x9c, 0xc0, 0xf3, 0xd0, 0x2d, 0x00, 0x3a, 0xd6, + 0x5c, 0xd2, 0xb3, 0x5d, 0x23, 0x79, 0x8f, 0x75, 0xc7, 0x98, 0x6b, 0xe0, 0x32, 0x95, 0x25, 0x4f, + 0xfd, 0x67, 0x1a, 0x6a, 0x13, 0xa7, 0x0e, 0x6d, 0x40, 0x5e, 0xc4, 0x14, 0x49, 0x7f, 0x85, 0x38, + 0x68, 0xc8, 0x23, 0x2a, 0x54, 0xd1, 0x9b, 0x50, 0x22, 0x32, 0xaa, 0x9e, 0x75, 0xba, 0x45, 0x96, + 0xc0, 0x8f, 0xbb, 0xa5, 0x69, 0x60, 0x81, 0xde, 0x86, 0x72, 0x00, 0x1f, 0x32, 0x90, 0x7d, 0x6a, + 0xda, 0x3c, 0x00, 0x1e, 0x69, 0x1f, 0xda, 0xa0, 0xd7, 0x42, 0x06, 0x99, 0x9b, 0x8e, 0x64, 0xa4, + 0xb9, 0x50, 0x90, 0xc6, 0xbe, 0xbe, 0xda, 0x84, 0xa5, 0xc8, 0x78, 0xd0, 0x13, 0x50, 0x66, 0x71, + 0xbf, 0x08, 0xfa, 0x45, 0x32, 0xaa, 0x34, 0xd4, 0x45, 0xc8, 0x8f, 0x2e, 0x43, 0x91, 0x35, 0x1e, + 0xeb, 0x02, 0xc2, 0xb2, 0xb8, 0x30, 0xd4, 0xc7, 0xef, 0xea, 0x9e, 0xfa, 0x3e, 0x54, 0xe3, 0x69, + 0x3c, 0xb6, 0xbd, 0x5d, 0x7b, 0x64, 0x19, 0xdc, 0x47, 0x1e, 0x8b, 0x0a, 0x7a, 0x05, 0xf2, 0x27, + 0xb6, 0x40, 0xc0, 0xd9, 0x6b, 0xf4, 0xc0, 0xa6, 0x24, 0x92, 0xea, 0x10, 0xda, 0xaa, 0x09, 0x68, + 0x3a, 0x1b, 0x92, 0xd0, 0xc5, 0x5b, 0xf1, 0x2e, 0x9e, 0x4a, 0xcc, 0xab, 0xcc, 0xee, 0xea, 0x13, + 0xc8, 0x73, 0xf0, 0x64, 0x40, 0xc8, 0x73, 0x7f, 0x92, 0xa8, 0xb3, 0x32, 0x7a, 0x1f, 0x40, 0xa7, + 0xd4, 0x35, 0x0f, 0x47, 0x61, 0x07, 0x6b, 0xb3, 0xc1, 0x77, 0xd3, 0xd7, 0xdb, 0xba, 0x22, 0x51, + 0xf8, 0x62, 0x68, 0x1a, 0x41, 0xe2, 0x88, 0x43, 0x75, 0x17, 0xaa, 0x71, 0xdb, 0x68, 0x16, 0x7e, + 0x79, 0x46, 0x16, 0x3e, 0x20, 0x83, 0x01, 0x95, 0xcc, 0x8a, 0x3c, 0x2f, 0xaf, 0xa8, 0x9f, 0xa6, + 0xa1, 0xc4, 0x36, 0x3d, 0x3f, 0x96, 0x09, 0x29, 0xc6, 0xd0, 0x34, 0x13, 0x4d, 0xa8, 0x89, 0x9c, + 0x65, 0x36, 0xc8, 0x84, 0xbe, 0x13, 0x00, 0x4f, 0x6e, 0xd1, 0x60, 0xdd, 0xcf, 0x86, 0x49, 0xb0, + 0xfd, 0xa5, 0xfc, 0x18, 0x76, 0xee, 0xd0, 0xeb, 0x50, 0xd0, 0x7b, 0x41, 0xae, 0xa8, 0x3a, 0xc3, + 0x9d, 0xaf, 0xba, 0xde, 0x1d, 0x6f, 0x72, 0x4d, 0x2c, 0x2d, 0xe4, 0xa7, 0x65, 0x82, 0x74, 0xea, + 0xdb, 0xcc, 0xaf, 0xd0, 0x89, 0x63, 0x4f, 0x15, 0xe0, 0x60, 0xf7, 0x7e, 0x67, 0x7b, 0xe7, 0xf6, + 0x4e, 0x6b, 0x5b, 0xe2, 0xcf, 0xf6, 0x76, 0x6b, 0x5b, 0xc9, 0x30, 0x3d, 0xdc, 0xba, 0xdf, 0x79, + 0xd0, 0xda, 0x56, 0xb2, 0xea, 0x1b, 0x50, 0x0e, 0x8e, 0x16, 0x8b, 0xc5, 0x74, 0xc3, 0x70, 0x89, + 0xe7, 0xc9, 0x59, 0xf7, 0xab, 0x3c, 0x97, 0x6e, 0x7f, 0x2c, 0x93, 0x89, 0x59, 0x2c, 0x2a, 0xaa, + 0x01, 0xb5, 0x09, 0x42, 0x80, 0xde, 0x80, 0xa2, 0x33, 0x3a, 0xd4, 0xfc, 0x85, 0x9b, 0x40, 0x10, + 0x9f, 0x97, 0x8f, 0x0e, 0x07, 0x66, 0xef, 0x2e, 0x39, 0xf5, 0xa7, 0xc9, 0x19, 0x1d, 0xde, 0x15, + 0xeb, 0x2b, 0x7a, 0xc9, 0x44, 0x7b, 0xf9, 0x69, 0x1a, 0x4a, 0xfe, 0x7e, 0x45, 0xff, 0x13, 0x45, + 0x0b, 0xff, 0x17, 0x4b, 0x22, 0x4b, 0x91, 0xfe, 0x23, 0x60, 0x71, 0x03, 0x56, 0x3c, 0xf3, 0xd8, + 0x22, 0x86, 0x16, 0x86, 0x83, 0xbc, 0xbb, 0x12, 0xae, 0x89, 0x86, 0x7b, 0x7e, 0x2c, 0x78, 0x27, + 0x57, 0xca, 0x2a, 0xb9, 0x3b, 0xb9, 0x52, 0x4e, 0xc9, 0xab, 0xbf, 0x4e, 0x83, 0x32, 0x79, 0x78, + 0xfe, 0x9d, 0x1f, 0xc3, 0xae, 0x22, 0x76, 0x48, 0x35, 0xc2, 0x3e, 0x22, 0x08, 0x88, 0x97, 0x71, + 0x85, 0x49, 0x5b, 0xbe, 0x50, 0xfd, 0x47, 0x1a, 0x4a, 0x3e, 0xd4, 0xa2, 0x97, 0x22, 0xc7, 0xb8, + 0x3a, 0x23, 0xcf, 0xe7, 0x2b, 0x86, 0x39, 0xfc, 0xf8, 0x90, 0x32, 0xe7, 0x1f, 0x52, 0xd2, 0xcf, + 0x18, 0xff, 0xaf, 0x58, 0xee, 0xdc, 0x7f, 0xc5, 0x5e, 0x00, 0x44, 0x6d, 0xaa, 0x0f, 0xb4, 0x13, + 0x9b, 0x9a, 0xd6, 0xb1, 0x26, 0x76, 0x88, 0x20, 0xd8, 0x0a, 0x6f, 0x79, 0xc0, 0x1b, 0xf6, 0x82, + 0xcd, 0x12, 0x50, 0xa5, 0xf3, 0xa6, 0xe4, 0x2f, 0x41, 0x41, 0xb2, 0x01, 0x91, 0x93, 0x97, 0xb5, + 0x20, 0x31, 0x9e, 0x8b, 0x24, 0xc6, 0x1b, 0x50, 0x1a, 0x12, 0xaa, 0x73, 0xbe, 0x28, 0xb2, 0x08, + 0x41, 0xfd, 0xc6, 0x6b, 0xb0, 0x14, 0xf9, 0x3b, 0xc2, 0x80, 0x6c, 0xb7, 0xf5, 0x9e, 0x92, 0x6a, + 0x14, 0x3f, 0xfd, 0xfc, 0x6a, 0x76, 0x97, 0x7c, 0xcc, 0x0e, 0x1a, 0x6e, 0x35, 0xdb, 0xad, 0xe6, + 0x5d, 0x25, 0xdd, 0x58, 0xfa, 0xf4, 0xf3, 0xab, 0x45, 0x4c, 0x78, 0x7a, 0xf0, 0x46, 0x1b, 0x96, + 0xa3, 0xab, 0x12, 0x3f, 0xd4, 0x08, 0xaa, 0xdb, 0x07, 0x7b, 0xf7, 0x76, 0x9a, 0x9b, 0xdd, 0x96, + 0xf6, 0xa0, 0xd3, 0x6d, 0x29, 0x69, 0x74, 0x19, 0x2e, 0xdc, 0xdb, 0x79, 0xb7, 0xdd, 0xd5, 0x9a, + 0xf7, 0x76, 0x5a, 0xbb, 0x5d, 0x6d, 0xb3, 0xdb, 0xdd, 0x6c, 0xde, 0x55, 0x32, 0x1b, 0x7f, 0x05, + 0xa8, 0x6d, 0x6e, 0x35, 0x77, 0x18, 0x19, 0x32, 0x7b, 0xba, 0x4c, 0xbf, 0xe6, 0x78, 0x12, 0xe7, + 0xcc, 0xc7, 0x1e, 0x8d, 0xb3, 0xb3, 0xcf, 0xe8, 0x36, 0xe4, 0x79, 0x7e, 0x07, 0x9d, 0xfd, 0xfa, + 0xa3, 0x31, 0x27, 0x1d, 0xcd, 0x3e, 0x86, 0x9f, 0xa2, 0x33, 0x9f, 0x83, 0x34, 0xce, 0xce, 0x4e, + 0x23, 0x0c, 0xe5, 0x30, 0x41, 0x33, 0xff, 0x79, 0x48, 0x63, 0x81, 0x8c, 0x35, 0xf3, 0x19, 0x46, + 0x89, 0xf3, 0x9f, 0x4b, 0x34, 0x16, 0xb8, 0x0f, 0xd0, 0x3d, 0x28, 0xfa, 0x81, 0xfd, 0xbc, 0x07, + 0x1c, 0x8d, 0xb9, 0xd9, 0x64, 0xb6, 0x04, 0x22, 0x01, 0x73, 0xf6, 0x6b, 0x94, 0xc6, 0x9c, 0xd4, + 0x38, 0xda, 0x81, 0x82, 0x0c, 0x7d, 0xe6, 0x3c, 0xca, 0x68, 0xcc, 0xcb, 0x0e, 0xb3, 0x49, 0x0b, + 0x33, 0x5b, 0xf3, 0xdf, 0xd8, 0x34, 0x16, 0xc8, 0xfa, 0xa3, 0x03, 0x80, 0x48, 0xba, 0x65, 0x81, + 0xc7, 0x33, 0x8d, 0x45, 0xb2, 0xf9, 0xa8, 0x03, 0xa5, 0x20, 0xfa, 0x9d, 0xfb, 0x94, 0xa5, 0x31, + 0x3f, 0xad, 0x8e, 0x1e, 0x42, 0x25, 0x1e, 0xf6, 0x2d, 0xf6, 0x40, 0xa5, 0xb1, 0x60, 0xbe, 0x9c, + 0xf9, 0x8f, 0xc7, 0x80, 0x8b, 0x3d, 0x58, 0x69, 0x2c, 0x98, 0x3e, 0x47, 0x1f, 0xc2, 0xca, 0x74, + 0x8c, 0xb6, 0xf8, 0xfb, 0x95, 0xc6, 0x39, 0x12, 0xea, 0x68, 0x08, 0x68, 0x46, 0x6c, 0x77, 0x8e, + 0xe7, 0x2c, 0x8d, 0xf3, 0xe4, 0xd7, 0x91, 0x01, 0xb5, 0xc9, 0x80, 0x69, 0xd1, 0xe7, 0x2d, 0x8d, + 0x85, 0x73, 0xed, 0x5b, 0xad, 0x2f, 0xbf, 0x59, 0x4d, 0x7f, 0xf5, 0xcd, 0x6a, 0xfa, 0xcf, 0xdf, + 0xac, 0xa6, 0x3f, 0xfb, 0x76, 0x35, 0xf5, 0xd5, 0xb7, 0xab, 0xa9, 0x3f, 0x7c, 0xbb, 0x9a, 0xfa, + 0xd1, 0xf3, 0xc7, 0x26, 0xed, 0x8f, 0x0e, 0xd7, 0x7b, 0xf6, 0xf0, 0x66, 0xf4, 0x45, 0xdf, 0xac, + 0x57, 0x86, 0x87, 0x05, 0x7e, 0x1d, 0xbe, 0xfc, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x38, 0xf1, + 0x86, 0x0d, 0x85, 0x28, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -5404,20 +5633,61 @@ func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - if m.BlockDataSize != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.BlockDataSize)) + if m.MaxTxBytes != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.MaxTxBytes)) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x30 } - if len(m.BlockData) > 0 { - for iNdEx := len(m.BlockData) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.BlockData[iNdEx]) - copy(dAtA[i:], m.BlockData[iNdEx]) - i = encodeVarintTypes(dAtA, i, uint64(len(m.BlockData[iNdEx]))) + if len(m.ByzantineValidators) > 0 { + for iNdEx := len(m.ByzantineValidators) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ByzantineValidators[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } i-- - dAtA[i] = 0xa + dAtA[i] = 0x2a } } + { + size, err := m.LocalLastCommit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.Txs) > 0 { + for iNdEx := len(m.Txs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Txs[iNdEx]) + copy(dAtA[i:], m.Txs[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Txs[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + { + size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0xa + } return len(dAtA) - i, nil } @@ -6686,20 +6956,20 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err } } if len(m.RefetchChunks) > 0 { - dAtA47 := make([]byte, len(m.RefetchChunks)*10) - var j46 int + dAtA45 := make([]byte, len(m.RefetchChunks)*10) + var j44 int for _, num := range m.RefetchChunks { for num >= 1<<7 { - dAtA47[j46] = uint8(uint64(num)&0x7f | 0x80) + dAtA45[j44] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j46++ + j44++ } - dAtA47[j46] = uint8(num) - j46++ + dAtA45[j44] = uint8(num) + j44++ } - i -= j46 - copy(dAtA[i:], dAtA47[:j46]) - i = encodeVarintTypes(dAtA, i, uint64(j46)) + i -= j44 + copy(dAtA[i:], dAtA45[:j44]) + i = encodeVarintTypes(dAtA, i, uint64(j44)) i-- dAtA[i] = 0x12 } @@ -6731,11 +7001,16 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - if len(m.BlockData) > 0 { - for iNdEx := len(m.BlockData) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.BlockData[iNdEx]) - copy(dAtA[i:], m.BlockData[iNdEx]) - i = encodeVarintTypes(dAtA, i, uint64(len(m.BlockData[iNdEx]))) + if len(m.TxRecords) > 0 { + for iNdEx := len(m.TxRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TxRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } i-- dAtA[i] = 0xa } @@ -6917,6 +7192,48 @@ func (m *CommitInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ExtendedCommitInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExtendedCommitInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExtendedCommitInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Votes) > 0 { + for iNdEx := len(m.Votes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Votes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Round != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Round)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *Event) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -7058,6 +7375,41 @@ func (m *TxResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TxRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TxRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TxRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Tx) > 0 { + i -= len(m.Tx) + copy(dAtA[i:], m.Tx) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Tx))) + i-- + dAtA[i] = 0x12 + } + if m.Action != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Action)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *Validator) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -7174,6 +7526,56 @@ func (m *VoteInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ExtendedVoteInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExtendedVoteInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExtendedVoteInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.VoteExtension) > 0 { + i -= len(m.VoteExtension) + copy(dAtA[i:], m.VoteExtension) + i = encodeVarintTypes(dAtA, i, uint64(len(m.VoteExtension))) + i-- + dAtA[i] = 0x1a + } + if m.SignedLastBlock { + i-- + if m.SignedLastBlock { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + { + size, err := m.Validator.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *Evidence) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -7199,12 +7601,12 @@ func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n55, err55 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err55 != nil { - return 0, err55 + n54, err54 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err54 != nil { + return 0, err54 } - i -= n55 - i = encodeVarintTypes(dAtA, i, uint64(n55)) + i -= n54 + i = encodeVarintTypes(dAtA, i, uint64(n54)) i-- dAtA[i] = 0x22 if m.Height != 0 { @@ -7765,14 +8167,28 @@ func (m *RequestPrepareProposal) Size() (n int) { } var l int _ = l - if len(m.BlockData) > 0 { - for _, b := range m.BlockData { + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Header.Size() + n += 1 + l + sovTypes(uint64(l)) + if len(m.Txs) > 0 { + for _, b := range m.Txs { l = len(b) n += 1 + l + sovTypes(uint64(l)) } } - if m.BlockDataSize != 0 { - n += 1 + sovTypes(uint64(m.BlockDataSize)) + l = m.LocalLastCommit.Size() + n += 1 + l + sovTypes(uint64(l)) + if len(m.ByzantineValidators) > 0 { + for _, e := range m.ByzantineValidators { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if m.MaxTxBytes != 0 { + n += 1 + sovTypes(uint64(m.MaxTxBytes)) } return n } @@ -8410,9 +8826,9 @@ func (m *ResponsePrepareProposal) Size() (n int) { } var l int _ = l - if len(m.BlockData) > 0 { - for _, b := range m.BlockData { - l = len(b) + if len(m.TxRecords) > 0 { + for _, e := range m.TxRecords { + l = e.Size() n += 1 + l + sovTypes(uint64(l)) } } @@ -8489,6 +8905,24 @@ func (m *CommitInfo) Size() (n int) { return n } +func (m *ExtendedCommitInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Round != 0 { + n += 1 + sovTypes(uint64(m.Round)) + } + if len(m.Votes) > 0 { + for _, e := range m.Votes { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + func (m *Event) Size() (n int) { if m == nil { return 0 @@ -8549,6 +8983,22 @@ func (m *TxResult) Size() (n int) { return n } +func (m *TxRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Action != 0 { + n += 1 + sovTypes(uint64(m.Action)) + } + l = len(m.Tx) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func (m *Validator) Size() (n int) { if m == nil { return 0 @@ -8593,6 +9043,24 @@ func (m *VoteInfo) Size() (n int) { return n } +func (m *ExtendedVoteInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Validator.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.SignedLastBlock { + n += 2 + } + l = len(m.VoteExtension) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func (m *Evidence) Size() (n int) { if m == nil { return 0 @@ -10984,7 +11452,7 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockData", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -11011,14 +11479,16 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.BlockData = append(m.BlockData, make([]byte, postIndex-iNdEx)) - copy(m.BlockData[len(m.BlockData)-1], dAtA[iNdEx:postIndex]) + m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} + } iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockDataSize", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Header", wireType) } - m.BlockDataSize = 0 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -11028,7 +11498,139 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.BlockDataSize |= int64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Header.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Txs", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Txs = append(m.Txs, make([]byte, postIndex-iNdEx)) + copy(m.Txs[len(m.Txs)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LocalLastCommit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.LocalLastCommit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ByzantineValidators", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ByzantineValidators = append(m.ByzantineValidators, Evidence{}) + if err := m.ByzantineValidators[len(m.ByzantineValidators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTxBytes", wireType) + } + m.MaxTxBytes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxTxBytes |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -14442,9 +15044,9 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockData", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TxRecords", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -14454,23 +15056,25 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.BlockData = append(m.BlockData, make([]byte, postIndex-iNdEx)) - copy(m.BlockData[len(m.BlockData)-1], dAtA[iNdEx:postIndex]) + m.TxRecords = append(m.TxRecords, &TxRecord{}) + if err := m.TxRecords[len(m.TxRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -14947,6 +15551,109 @@ func (m *CommitInfo) Unmarshal(dAtA []byte) error { } return nil } +func (m *ExtendedCommitInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExtendedCommitInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExtendedCommitInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Round", wireType) + } + m.Round = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Round |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Votes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Votes = append(m.Votes, ExtendedVoteInfo{}) + if err := m.Votes[len(m.Votes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Event) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -15356,6 +16063,109 @@ func (m *TxResult) Unmarshal(dAtA []byte) error { } return nil } +func (m *TxRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TxRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TxRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Action", wireType) + } + m.Action = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Action |= TxRecord_TxAction(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tx", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tx = append(m.Tx[:0], dAtA[iNdEx:postIndex]...) + if m.Tx == nil { + m.Tx = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Validator) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -15664,6 +16474,143 @@ func (m *VoteInfo) Unmarshal(dAtA []byte) error { } return nil } +func (m *ExtendedVoteInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExtendedVoteInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExtendedVoteInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Validator", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Validator.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SignedLastBlock", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SignedLastBlock = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VoteExtension", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.VoteExtension = append(m.VoteExtension[:0], dAtA[iNdEx:postIndex]...) + if m.VoteExtension == nil { + m.VoteExtension = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Evidence) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/appveyor.yml b/appveyor.yml index 4aa8c2abb..afaab5b83 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,12 +1,12 @@ version: 1.0.{build} configuration: Release platform: -- x64 -- x86 + - x64 + - x86 clone_folder: c:\go\path\src\github.com\tendermint\tendermint before_build: -- cmd: set GOPATH=%GOROOT%\path -- cmd: set PATH=%GOPATH%\bin;%PATH% + - cmd: set GOPATH=%GOROOT%\path + - cmd: set PATH=%GOPATH%\bin;%PATH% build_script: -- cmd: make test + - cmd: make test test: off diff --git a/behaviour/doc.go b/behaviour/doc.go index 40061e095..10c8d3d53 100644 --- a/behaviour/doc.go +++ b/behaviour/doc.go @@ -1,10 +1,10 @@ /* -Package Behaviour provides a mechanism for reactors to report behaviour of peers. +Package Behavior provides a mechanism for reactors to report behavior of peers. -Instead of a reactor calling the switch directly it will call the behaviour module which will +Instead of a reactor calling the switch directly it will call the behavior module which will handle the stoping and marking peer as good on behalf of the reactor. -There are four different behaviours a reactor can report. +There are four different behaviors a reactor can report. 1. bad message @@ -39,4 +39,4 @@ type blockPart struct { This message will request the peer be marked as good */ -package behaviour +package behaviour //nolint:misspell diff --git a/behaviour/peer_behaviour.go b/behaviour/peer_behaviour.go index f7cfd00f0..b00b03a8d 100644 --- a/behaviour/peer_behaviour.go +++ b/behaviour/peer_behaviour.go @@ -1,12 +1,12 @@ -package behaviour +package behaviour //nolint:misspell import ( "github.com/tendermint/tendermint/p2p" ) -// PeerBehaviour is a struct describing a behaviour a peer performed. +// PeerBehaviour is a struct describing a behavior a peer performed. // `peerID` identifies the peer and reason characterizes the specific -// behaviour performed by the peer. +// behavior performed by the peer. type PeerBehaviour struct { peerID p2p.ID reason interface{} diff --git a/behaviour/reporter.go b/behaviour/reporter.go index 8dc10389e..8540f490b 100644 --- a/behaviour/reporter.go +++ b/behaviour/reporter.go @@ -1,4 +1,4 @@ -package behaviour +package behaviour //nolint:misspell import ( "errors" @@ -7,13 +7,13 @@ import ( "github.com/tendermint/tendermint/p2p" ) -// Reporter provides an interface for reactors to report the behaviour +// Reporter provides an interface for reactors to report the behavior // of peers synchronously to other components. type Reporter interface { - Report(behaviour PeerBehaviour) error + Report(behavior PeerBehaviour) error } -// SwitchReporter reports peer behaviour to an internal Switch. +// SwitchReporter reports peer behavior to an internal Switch. type SwitchReporter struct { sw *p2p.Switch } @@ -25,14 +25,14 @@ func NewSwitchReporter(sw *p2p.Switch) *SwitchReporter { } } -// Report reports the behaviour of a peer to the Switch. -func (spbr *SwitchReporter) Report(behaviour PeerBehaviour) error { - peer := spbr.sw.Peers().Get(behaviour.peerID) +// Report reports the behavior of a peer to the Switch. +func (spbr *SwitchReporter) Report(behavior PeerBehaviour) error { + peer := spbr.sw.Peers().Get(behavior.peerID) if peer == nil { return errors.New("peer not found") } - switch reason := behaviour.reason.(type) { + switch reason := behavior.reason.(type) { case consensusVote, blockPart: spbr.sw.MarkPeerAsGood(peer) case badMessage: @@ -48,14 +48,14 @@ func (spbr *SwitchReporter) Report(behaviour PeerBehaviour) error { // MockReporter is a concrete implementation of the Reporter // interface used in reactor tests to ensure reactors report the correct -// behaviour in manufactured scenarios. +// behavior in manufactured scenarios. type MockReporter struct { mtx tmsync.RWMutex pb map[p2p.ID][]PeerBehaviour } // NewMockReporter returns a Reporter which records all reported -// behaviours in memory. +// behaviors in memory. func NewMockReporter() *MockReporter { return &MockReporter{ pb: map[p2p.ID][]PeerBehaviour{}, @@ -63,15 +63,15 @@ func NewMockReporter() *MockReporter { } // Report stores the PeerBehaviour produced by the peer identified by peerID. -func (mpbr *MockReporter) Report(behaviour PeerBehaviour) error { +func (mpbr *MockReporter) Report(behavior PeerBehaviour) error { mpbr.mtx.Lock() defer mpbr.mtx.Unlock() - mpbr.pb[behaviour.peerID] = append(mpbr.pb[behaviour.peerID], behaviour) + mpbr.pb[behavior.peerID] = append(mpbr.pb[behavior.peerID], behavior) return nil } -// GetBehaviours returns all behaviours reported on the peer identified by peerID. +// GetBehaviours returns all behaviors reported on the peer identified by peerID. func (mpbr *MockReporter) GetBehaviours(peerID p2p.ID) []PeerBehaviour { mpbr.mtx.RLock() defer mpbr.mtx.RUnlock() diff --git a/behaviour/reporter_test.go b/behaviour/reporter_test.go index 330505bd2..38a5870a4 100644 --- a/behaviour/reporter_test.go +++ b/behaviour/reporter_test.go @@ -1,41 +1,41 @@ -package behaviour_test +package behaviour_test //nolint:misspell import ( "sync" "testing" - bh "github.com/tendermint/tendermint/behaviour" + bh "github.com/tendermint/tendermint/behaviour" //nolint:misspell "github.com/tendermint/tendermint/p2p" ) // TestMockReporter tests the MockReporter's ability to store reported -// peer behaviour in memory indexed by the peerID. +// peer behavior in memory indexed by the peerID. func TestMockReporter(t *testing.T) { var peerID p2p.ID = "MockPeer" pr := bh.NewMockReporter() - behaviours := pr.GetBehaviours(peerID) - if len(behaviours) != 0 { - t.Error("Expected to have no behaviours reported") + behaviors := pr.GetBehaviours(peerID) + if len(behaviors) != 0 { + t.Error("Expected to have no behaviors reported") } badMessage := bh.BadMessage(peerID, "bad message") if err := pr.Report(badMessage); err != nil { t.Error(err) } - behaviours = pr.GetBehaviours(peerID) - if len(behaviours) != 1 { - t.Error("Expected the peer have one reported behaviour") + behaviors = pr.GetBehaviours(peerID) + if len(behaviors) != 1 { + t.Error("Expected the peer have one reported behavior") } - if behaviours[0] != badMessage { + if behaviors[0] != badMessage { t.Error("Expected Bad Message to have been reported") } } type scriptItem struct { - peerID p2p.ID - behaviour bh.PeerBehaviour + peerID p2p.ID + behavior bh.PeerBehaviour } // equalBehaviours returns true if a and b contain the same PeerBehaviours with @@ -44,26 +44,26 @@ func equalBehaviours(a []bh.PeerBehaviour, b []bh.PeerBehaviour) bool { aHistogram := map[bh.PeerBehaviour]int{} bHistogram := map[bh.PeerBehaviour]int{} - for _, behaviour := range a { - aHistogram[behaviour]++ + for _, behavior := range a { + aHistogram[behavior]++ } - for _, behaviour := range b { - bHistogram[behaviour]++ + for _, behavior := range b { + bHistogram[behavior]++ } if len(aHistogram) != len(bHistogram) { return false } - for _, behaviour := range a { - if aHistogram[behaviour] != bHistogram[behaviour] { + for _, behavior := range a { + if aHistogram[behavior] != bHistogram[behavior] { return false } } - for _, behaviour := range b { - if bHistogram[behaviour] != aHistogram[behaviour] { + for _, behavior := range b { + if bHistogram[behavior] != aHistogram[behavior] { return false } } @@ -72,8 +72,8 @@ func equalBehaviours(a []bh.PeerBehaviour, b []bh.PeerBehaviour) bool { } // TestEqualPeerBehaviours tests that equalBehaviours can tell that two slices -// of peer behaviours can be compared for the behaviours they contain and the -// freequencies that those behaviours occur. +// of peer behaviors can be compared for the behaviors they contain and the +// freequencies that those behaviors occur. func TestEqualPeerBehaviours(t *testing.T) { var ( peerID p2p.ID = "MockPeer" @@ -85,7 +85,7 @@ func TestEqualPeerBehaviours(t *testing.T) { }{ // Empty sets {[]bh.PeerBehaviour{}, []bh.PeerBehaviour{}}, - // Single behaviours + // Single behaviors {[]bh.PeerBehaviour{consensusVote}, []bh.PeerBehaviour{consensusVote}}, // Equal Frequencies {[]bh.PeerBehaviour{consensusVote, consensusVote}, @@ -100,9 +100,9 @@ func TestEqualPeerBehaviours(t *testing.T) { }{ // Comparing empty sets to non empty sets {[]bh.PeerBehaviour{}, []bh.PeerBehaviour{consensusVote}}, - // Different behaviours + // Different behaviors {[]bh.PeerBehaviour{consensusVote}, []bh.PeerBehaviour{blockPart}}, - // Same behaviour with different frequencies + // Same behavior with different frequencies {[]bh.PeerBehaviour{consensusVote}, []bh.PeerBehaviour{consensusVote, consensusVote}}, } @@ -128,8 +128,8 @@ func TestEqualPeerBehaviours(t *testing.T) { func TestMockPeerBehaviourReporterConcurrency(t *testing.T) { var ( behaviourScript = []struct { - peerID p2p.ID - behaviours []bh.PeerBehaviour + peerID p2p.ID + behaviors []bh.PeerBehaviour }{ {"1", []bh.PeerBehaviour{bh.ConsensusVote("1", "")}}, {"2", []bh.PeerBehaviour{bh.ConsensusVote("2", ""), bh.ConsensusVote("2", ""), bh.ConsensusVote("2", "")}}, @@ -166,7 +166,7 @@ func TestMockPeerBehaviourReporterConcurrency(t *testing.T) { for { select { case pb := <-scriptItems: - if err := pr.Report(pb.behaviour); err != nil { + if err := pr.Report(pb.behavior); err != nil { t.Error(err) } case <-done: @@ -181,7 +181,7 @@ func TestMockPeerBehaviourReporterConcurrency(t *testing.T) { go func() { defer sendingWg.Done() for _, item := range behaviourScript { - for _, reason := range item.behaviours { + for _, reason := range item.behaviors { scriptItems <- scriptItem{item.peerID, reason} } } @@ -197,9 +197,9 @@ func TestMockPeerBehaviourReporterConcurrency(t *testing.T) { for _, items := range behaviourScript { reported := pr.GetBehaviours(items.peerID) - if !equalBehaviours(reported, items.behaviours) { + if !equalBehaviours(reported, items.behaviors) { t.Errorf("expected peer %s to have behaved \nExpected: %#v \nGot %#v \n", - items.peerID, items.behaviours, reported) + items.peerID, items.behaviors, reported) } } } diff --git a/blockchain/v0/reactor.go b/blockchain/v0/reactor.go index c14d2d34a..93a1e7174 100644 --- a/blockchain/v0/reactor.go +++ b/blockchain/v0/reactor.go @@ -360,14 +360,20 @@ FOR_LOOP: didProcessCh <- struct{}{} } - firstParts := first.MakePartSet(types.BlockPartSizeBytes) + firstParts, err := first.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + bcR.Logger.Error("failed to make ", + "height", first.Height, + "err", err.Error()) + break FOR_LOOP + } firstPartSetHeader := firstParts.Header() firstID := types.BlockID{Hash: first.Hash(), PartSetHeader: firstPartSetHeader} // Finally, verify the first block using the second's commit // NOTE: we can probably make this more efficient, but note that calling // first.Hash() doesn't verify the tx contents, so MakePartSet() is // currently necessary. - err := state.Validators.VerifyCommitLight( + err = state.Validators.VerifyCommitLight( chainID, firstID, first.Height, second.LastCommit) if err == nil { diff --git a/blockchain/v0/reactor_test.go b/blockchain/v0/reactor_test.go index 565ce7834..6184b5b78 100644 --- a/blockchain/v0/reactor_test.go +++ b/blockchain/v0/reactor_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" @@ -15,7 +16,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/proxy" sm "github.com/tendermint/tendermint/state" @@ -53,6 +54,7 @@ type BlockchainReactorPair struct { } func newBlockchainReactor( + t *testing.T, logger log.Logger, genDoc *types.GenesisDoc, privVals []types.PrivValidator, @@ -79,6 +81,18 @@ func newBlockchainReactor( panic(fmt.Errorf("error constructing state from genesis file: %w", err)) } + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + // Make the BlockchainReactor itself. // NOTE we have to create and commit the blocks first because // pool.height is determined from the store. @@ -86,7 +100,7 @@ func newBlockchainReactor( db := dbm.NewMemDB() stateStore = sm.NewStore(db) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mock.Mempool{}, sm.EmptyEvidencePool{}) + mp, sm.EmptyEvidencePool{}) if err = stateStore.Save(state); err != nil { panic(err) } @@ -115,7 +129,8 @@ func newBlockchainReactor( thisBlock := sf.MakeBlock(state, blockHeight, lastCommit) - thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes) + thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()} state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock) @@ -141,8 +156,8 @@ func TestNoBlockResponse(t *testing.T) { reactorPairs := make([]BlockchainReactorPair, 2) - reactorPairs[0] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, maxBlockHeight) - reactorPairs[1] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) + reactorPairs[0] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight) + reactorPairs[1] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) p2p.MakeConnectedSwitches(config.P2P, 2, func(i int, s *p2p.Switch) *p2p.Switch { s.AddReactor("BLOCKCHAIN", reactorPairs[i].reactor) @@ -203,7 +218,7 @@ func TestBadBlockStopsPeer(t *testing.T) { // Other chain needs a different validator set otherGenDoc, otherPrivVals := randGenesisDoc(1, false, 30) - otherChain := newBlockchainReactor(log.TestingLogger(), otherGenDoc, otherPrivVals, maxBlockHeight) + otherChain := newBlockchainReactor(t, log.TestingLogger(), otherGenDoc, otherPrivVals, maxBlockHeight) defer func() { err := otherChain.reactor.Stop() @@ -214,10 +229,10 @@ func TestBadBlockStopsPeer(t *testing.T) { reactorPairs := make([]BlockchainReactorPair, 4) - reactorPairs[0] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, maxBlockHeight) - reactorPairs[1] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) - reactorPairs[2] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) - reactorPairs[3] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) + reactorPairs[0] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight) + reactorPairs[1] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) + reactorPairs[2] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) + reactorPairs[3] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) switches := p2p.MakeConnectedSwitches(config.P2P, 4, func(i int, s *p2p.Switch) *p2p.Switch { s.AddReactor("BLOCKCHAIN", reactorPairs[i].reactor) @@ -255,7 +270,7 @@ func TestBadBlockStopsPeer(t *testing.T) { // race, but can't be easily avoided. reactorPairs[3].reactor.store = otherChain.reactor.store - lastReactorPair := newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) + lastReactorPair := newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) reactorPairs = append(reactorPairs, lastReactorPair) switches = append(switches, p2p.MakeConnectedSwitches(config.P2P, 1, func(i int, s *p2p.Switch) *p2p.Switch { diff --git a/blockchain/v1/reactor.go b/blockchain/v1/reactor.go index c4c61ec51..4b12f70e9 100644 --- a/blockchain/v1/reactor.go +++ b/blockchain/v1/reactor.go @@ -5,7 +5,7 @@ import ( "reflect" "time" - "github.com/tendermint/tendermint/behaviour" + "github.com/tendermint/tendermint/behaviour" //nolint:misspell bc "github.com/tendermint/tendermint/blockchain" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/p2p" @@ -100,7 +100,7 @@ func NewBlockchainReactor(state sm.State, blockExec *sm.BlockExecutor, store *st fsm := NewFSM(startHeight, bcR) bcR.fsm = fsm bcR.BaseReactor = *p2p.NewBaseReactor("BlockchainReactor", bcR) - // bcR.swReporter = behaviour.NewSwitchReporter(bcR.BaseReactor.Switch) + // bcR.swReporter = behavior.NewSwitchReporter(bcR.BaseReactor.Switch) return bcR } @@ -465,7 +465,13 @@ func (bcR *BlockchainReactor) processBlock() error { chainID := bcR.initialState.ChainID - firstParts := first.MakePartSet(types.BlockPartSizeBytes) + firstParts, err := first.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + bcR.Logger.Error("failed to make ", + "height", first.Height, + "err", err.Error()) + return err + } firstPartSetHeader := firstParts.Header() firstID := types.BlockID{Hash: first.Hash(), PartSetHeader: firstPartSetHeader} // Finally, verify the first block using the second's commit diff --git a/blockchain/v1/reactor_test.go b/blockchain/v1/reactor_test.go index c0f371905..53bcc36fd 100644 --- a/blockchain/v1/reactor_test.go +++ b/blockchain/v1/reactor_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" @@ -16,11 +17,12 @@ import ( abci "github.com/tendermint/tendermint/abci/types" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" "github.com/tendermint/tendermint/p2p" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/proxy" sm "github.com/tendermint/tendermint/state" + sf "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/store" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" @@ -110,6 +112,18 @@ func newBlockchainReactor( panic(fmt.Errorf("error constructing state from genesis file: %w", err)) } + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + // Make the BlockchainReactor itself. // NOTE we have to create and commit the blocks first because // pool.height is determined from the store. @@ -117,7 +131,7 @@ func newBlockchainReactor( db := dbm.NewMemDB() stateStore = sm.NewStore(db) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mock.Mempool{}, sm.EmptyEvidencePool{}) + mp, sm.EmptyEvidencePool{}) if err = stateStore.Save(state); err != nil { panic(err) } @@ -133,9 +147,10 @@ func newBlockchainReactor( lastCommit = types.NewCommit(vote.Height, vote.Round, lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) } - thisBlock := makeBlock(blockHeight, state, lastCommit) + thisBlock := sf.MakeBlock(state, blockHeight, lastCommit) - thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes) + thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()} state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock) @@ -345,21 +360,6 @@ outerFor: assert.True(t, lastReactorPair.bcR.Switch.Peers().Size() < len(reactorPairs)-1) } -//---------------------------------------------- -// utility funcs - -func makeTxs(height int64) (txs []types.Tx) { - for i := 0; i < 10; i++ { - txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) - } - return txs -} - -func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block { - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address) - return block -} - type testApp struct { abci.BaseApplication } diff --git a/blockchain/v2/processor.go b/blockchain/v2/processor.go index f9036f3b9..44bf934fd 100644 --- a/blockchain/v2/processor.go +++ b/blockchain/v2/processor.go @@ -158,11 +158,12 @@ func (state *pcState) handle(event Event) (Event, error) { return noOp, nil } - var ( - first, second = firstItem.block, secondItem.block - firstParts = first.MakePartSet(types.BlockPartSizeBytes) - firstID = types.BlockID{Hash: first.Hash(), PartSetHeader: firstParts.Header()} - ) + first, second := firstItem.block, secondItem.block + firstParts, err := first.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + panic(fmt.Sprintf("failed to make part set, height %d: %v ", first.Height, err.Error())) + } + firstID := types.BlockID{Hash: first.Hash(), PartSetHeader: firstParts.Header()} // verify if +second+ last commit "confirms" +first+ block err = state.context.verifyCommit(tmState.ChainID, firstID, first.Height, second.LastCommit) diff --git a/blockchain/v2/processor_test.go b/blockchain/v2/processor_test.go index 6bc36b2d3..04ce05b6e 100644 --- a/blockchain/v2/processor_test.go +++ b/blockchain/v2/processor_test.go @@ -82,7 +82,7 @@ func executeProcessorTests(t *testing.T, tests []testFields) { } }() - // First step must always initialise the currentState as state. + // First step must always initialize the currentState as state. if step.currentState != nil { state = makeState(step.currentState) } diff --git a/blockchain/v2/reactor.go b/blockchain/v2/reactor.go index 9dea749d7..3b3a236e1 100644 --- a/blockchain/v2/reactor.go +++ b/blockchain/v2/reactor.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - "github.com/tendermint/tendermint/behaviour" + "github.com/tendermint/tendermint/behaviour" //nolint:misspell bc "github.com/tendermint/tendermint/blockchain" "github.com/tendermint/tendermint/libs/log" tmsync "github.com/tendermint/tendermint/libs/sync" @@ -139,7 +139,7 @@ func (r *BlockchainReactor) Start() error { return nil } -// startSync begins a fast sync, signalled by r.events being non-nil. If state is non-nil, +// startSync begins a fast sync, signaled by r.events being non-nil. If state is non-nil, // the scheduler and processor is updated with this state on startup. func (r *BlockchainReactor) startSync(state *state.State) error { r.mtx.Lock() diff --git a/blockchain/v2/reactor_test.go b/blockchain/v2/reactor_test.go index 1e84ee7de..f5ca11421 100644 --- a/blockchain/v2/reactor_test.go +++ b/blockchain/v2/reactor_test.go @@ -10,16 +10,17 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/behaviour" + "github.com/tendermint/tendermint/behaviour" //nolint:misspell bc "github.com/tendermint/tendermint/blockchain" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/service" - "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p/conn" bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain" @@ -143,8 +144,8 @@ type testReactorParams struct { mockA bool } -func newTestReactor(p testReactorParams) *BlockchainReactor { - store, state, _ := newReactorStore(p.genDoc, p.privVals, p.startHeight) +func newTestReactor(t *testing.T, p testReactorParams) *BlockchainReactor { + store, state, _ := newReactorStore(t, p.genDoc, p.privVals, p.startHeight) reporter := behaviour.NewMockReporter() var appl blockApplier @@ -152,6 +153,18 @@ func newTestReactor(p testReactorParams) *BlockchainReactor { if p.mockA { appl = &mockBlockApplier{} } else { + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + app := &testApp{} cc := proxy.NewLocalClientCreator(app) proxyApp := proxy.NewAppConns(cc) @@ -161,7 +174,7 @@ func newTestReactor(p testReactorParams) *BlockchainReactor { } db := dbm.NewMemDB() stateStore := sm.NewStore(db) - appl = sm.NewBlockExecutor(stateStore, p.logger, proxyApp.Consensus(), mock.Mempool{}, sm.EmptyEvidencePool{}) + appl = sm.NewBlockExecutor(stateStore, p.logger, proxyApp.Consensus(), mp, sm.EmptyEvidencePool{}) if err = stateStore.Save(state); err != nil { panic(err) } @@ -302,7 +315,7 @@ func newTestReactor(p testReactorParams) *BlockchainReactor { // t.Run(tt.name, func(t *testing.T) { // reactor := newTestReactor(params) // reactor.Start() -// reactor.reporter = behaviour.NewMockReporter() +// reactor.reporter = behavior.NewMockReporter() // mockSwitch := &mockSwitchIo{switchedToConsensus: false} // reactor.io = mockSwitch // // time for go routines to start @@ -392,7 +405,7 @@ func TestReactorHelperMode(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - reactor := newTestReactor(params) + reactor := newTestReactor(t, params) mockSwitch := &mockSwitchIo{switchedToConsensus: false} reactor.io = mockSwitch err := reactor.Start() @@ -435,7 +448,7 @@ func TestReactorSetSwitchNil(t *testing.T) { defer os.RemoveAll(config.RootDir) genDoc, privVals := randGenesisDoc(config.ChainID(), 1, false, 30) - reactor := newTestReactor(testReactorParams{ + reactor := newTestReactor(t, testReactorParams{ logger: log.TestingLogger(), genDoc: genDoc, privVals: privVals, @@ -474,6 +487,7 @@ func randGenesisDoc(chainID string, numValidators int, randPower bool, minPower // Why are we importing the entire blockExecutor dependency graph here // when we have the facilities to func newReactorStore( + t *testing.T, genDoc *types.GenesisDoc, privVals []types.PrivValidator, maxBlockHeight int64) (*store.BlockStore, sm.State, *sm.BlockExecutor) { @@ -496,10 +510,22 @@ func newReactorStore( panic(fmt.Errorf("error constructing state from genesis file: %w", err)) } + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + db := dbm.NewMemDB() stateStore = sm.NewStore(db) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mock.Mempool{}, sm.EmptyEvidencePool{}) + mp, sm.EmptyEvidencePool{}) if err = stateStore.Save(state); err != nil { panic(err) } @@ -527,7 +553,9 @@ func newReactorStore( thisBlock := sf.MakeBlock(state, blockHeight, lastCommit) - thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes) + thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) + blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()} state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock) diff --git a/blockchain/v2/scheduler_test.go b/blockchain/v2/scheduler_test.go index 762ffd2c5..5d4ebd976 100644 --- a/blockchain/v2/scheduler_test.go +++ b/blockchain/v2/scheduler_test.go @@ -2225,7 +2225,7 @@ func TestScHandle(t *testing.T) { t.Run(tt.name, func(t *testing.T) { var sc *scheduler for i, step := range tt.steps { - // First step must always initialise the currentState as state. + // First step must always initialize the currentState as state. if step.currentSc != nil { sc = newTestScheduler(*step.currentSc) } diff --git a/cmd/tendermint/commands/init.go b/cmd/tendermint/commands/init.go index 5d80a41ca..e2eae6eef 100644 --- a/cmd/tendermint/commands/init.go +++ b/cmd/tendermint/commands/init.go @@ -14,7 +14,7 @@ import ( tmtime "github.com/tendermint/tendermint/types/time" ) -// InitFilesCmd initialises a fresh Tendermint Core instance. +// InitFilesCmd initializes a fresh Tendermint Core instance. var InitFilesCmd = &cobra.Command{ Use: "init", Short: "Initialize Tendermint", diff --git a/cmd/tendermint/commands/light.go b/cmd/tendermint/commands/light.go index d98b8cded..2bab77213 100644 --- a/cmd/tendermint/commands/light.go +++ b/cmd/tendermint/commands/light.go @@ -101,7 +101,7 @@ func init() { } func runProxy(cmd *cobra.Command, args []string) error { - // Initialise logger. + // Initialize logger. logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) var option log.Option if verbose { diff --git a/config/config.go b/config/config.go index d052b40ae..cdd384dd0 100644 --- a/config/config.go +++ b/config/config.go @@ -370,7 +370,7 @@ type RPCConfig struct { // // Enabling this parameter will cause the WebSocket connection to be closed // instead if it cannot read fast enough, allowing for greater - // predictability in subscription behaviour. + // predictability in subscription behavior. CloseOnSlowClient bool `mapstructure:"experimental_close_on_slow_client"` // How long to wait for a tx to be committed during /broadcast_tx_commit diff --git a/config/toml.go b/config/toml.go index ad40b1efc..c57b4db84 100644 --- a/config/toml.go +++ b/config/toml.go @@ -230,7 +230,7 @@ experimental_websocket_write_buffer_size = {{ .RPC.WebSocketWriteBufferSize }} # # Enabling this experimental parameter will cause the WebSocket connection to # be closed instead if it cannot read fast enough, allowing for greater -# predictability in subscription behaviour. +# predictability in subscription behavior. experimental_close_on_slow_client = {{ .RPC.CloseOnSlowClient }} # How long to wait for a tx to be committed during /broadcast_tx_commit. diff --git a/consensus/byzantine_test.go b/consensus/byzantine_test.go index dd5febcbd..594c7d9a2 100644 --- a/consensus/byzantine_test.go +++ b/consensus/byzantine_test.go @@ -211,9 +211,11 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { } proposerAddr := lazyProposer.privValidatorPubKey.Address() - block, blockParts := lazyProposer.blockExec.CreateProposalBlock( - lazyProposer.Height, lazyProposer.state, commit, proposerAddr, - ) + block, err := lazyProposer.blockExec.CreateProposalBlock( + lazyProposer.Height, lazyProposer.state, commit, proposerAddr, nil) + require.NoError(t, err) + blockParts, err := block.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) // Flush the WAL. Otherwise, we may not recompute the same proposal to sign, // and the privValidator will refuse to sign anything. @@ -461,7 +463,10 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int32, cs *St // Avoid sending on internalMsgQueue and running consensus state. // Create a new proposal block from state/txs from the mempool. - block1, blockParts1 := cs.createProposalBlock() + block1, err := cs.createProposalBlock() + require.NoError(t, err) + blockParts1, err := block1.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) polRound, propBlockID := cs.ValidRound, types.BlockID{Hash: block1.Hash(), PartSetHeader: blockParts1.Header()} proposal1 := types.NewProposal(height, round, polRound, propBlockID) p1 := proposal1.ToProto() @@ -475,7 +480,10 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int32, cs *St deliverTxsRange(cs, 0, 1) // Create a new proposal block from state/txs from the mempool. - block2, blockParts2 := cs.createProposalBlock() + block2, err := cs.createProposalBlock() + require.NoError(t, err) + blockParts2, err := block2.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) polRound, propBlockID = cs.ValidRound, types.BlockID{Hash: block2.Hash(), PartSetHeader: blockParts2.Header()} proposal2 := types.NewProposal(height, round, polRound, propBlockID) p2 := proposal2.ToProto() diff --git a/consensus/common_test.go b/consensus/common_test.go index 09512f49d..a8375279c 100644 --- a/consensus/common_test.go +++ b/consensus/common_test.go @@ -201,13 +201,17 @@ func startTestRound(cs *State, height int64, round int32) { // Create proposal block from cs1 but sign it with vs. func decideProposal( + t *testing.T, cs1 *State, vs *validatorStub, height int64, round int32, ) (proposal *types.Proposal, block *types.Block) { cs1.mtx.Lock() - block, blockParts := cs1.createProposalBlock() + block, err := cs1.createProposalBlock() + require.NoError(t, err) + blockParts, err := block.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) validRound := cs1.ValidRound chainID := cs1.state.ChainID cs1.mtx.Unlock() diff --git a/consensus/mempool_test.go b/consensus/mempool_test.go index f99dcd248..87321cdda 100644 --- a/consensus/mempool_test.go +++ b/consensus/mempool_test.go @@ -259,7 +259,20 @@ func (app *CounterApplication) Commit() abci.ResponseCommit { func (app *CounterApplication) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{BlockData: req.BlockData} + + trs := make([]*abci.TxRecord, 0, len(req.Txs)) + var totalBytes int64 + for _, tx := range req.Txs { + totalBytes += int64(len(tx)) + if totalBytes > req.MaxTxBytes { + break + } + trs = append(trs, &abci.TxRecord{ + Action: abci.TxRecord_UNMODIFIED, + Tx: tx, + }) + } + return abci.ResponsePrepareProposal{TxRecords: trs} } func (app *CounterApplication) ProcessProposal( diff --git a/consensus/replay.go b/consensus/replay.go index 9fd59a40e..8e378113e 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -55,7 +55,7 @@ func (cs *State) readReplayMessage(msg *TimedWALMessage, newStepSub types.Subscr return fmt.Errorf("roundState mismatch. Got %v; Expected %v", m2, m) } case <-newStepSub.Cancelled(): - return fmt.Errorf("failed to read off newStepSub.Out(). newStepSub was cancelled") + return fmt.Errorf("failed to read off newStepSub.Out(). newStepSub was canceled") case <-ticker: return fmt.Errorf("failed to read off newStepSub.Out()") } diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 55dc175fd..61bc5f438 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -99,7 +99,7 @@ func startNewStateAndWaitForBlock(t *testing.T, consensusReplayConfig *cfg.Confi select { case <-newBlockSub.Out(): case <-newBlockSub.Cancelled(): - t.Fatal("newBlockSub was cancelled") + t.Fatal("newBlockSub was canceled") case <-time.After(120 * time.Second): t.Fatal("Timed out waiting for new block (see trace above)") } @@ -363,9 +363,11 @@ func TestSimulateValidatorsChange(t *testing.T) { require.NoError(t, err) newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower) err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx1, nil, mempl.TxInfo{}) - assert.Nil(t, err) - propBlock, _ := css[0].createProposalBlock() // changeProposer(t, cs1, vs2) - propBlockParts := propBlock.MakePartSet(partSize) + assert.NoError(t, err) + propBlock, err := css[0].createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} proposal := types.NewProposal(vss[1].Height, round, -1, blockID) @@ -393,9 +395,11 @@ func TestSimulateValidatorsChange(t *testing.T) { require.NoError(t, err) updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25) err = assertMempool(css[0].txNotifier).CheckTx(updateValidatorTx1, nil, mempl.TxInfo{}) - assert.Nil(t, err) - propBlock, _ = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) - propBlockParts = propBlock.MakePartSet(partSize) + assert.NoError(t, err) + propBlock, err = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) + propBlockParts, err = propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID = types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} proposal = types.NewProposal(vss[2].Height, round, -1, blockID) @@ -430,9 +434,11 @@ func TestSimulateValidatorsChange(t *testing.T) { require.NoError(t, err) newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower) err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx3, nil, mempl.TxInfo{}) - assert.Nil(t, err) - propBlock, _ = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) - propBlockParts = propBlock.MakePartSet(partSize) + assert.NoError(t, err) + propBlock, err = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) + propBlockParts, err = propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID = types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} newVss := make([]*validatorStub, nVals+1) copy(newVss, vss[:nVals+1]) @@ -505,9 +511,11 @@ func TestSimulateValidatorsChange(t *testing.T) { incrementHeight(vss...) removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0) err = assertMempool(css[0].txNotifier).CheckTx(removeValidatorTx3, nil, mempl.TxInfo{}) - assert.Nil(t, err) - propBlock, _ = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) - propBlockParts = propBlock.MakePartSet(partSize) + assert.NoError(t, err) + propBlock, err = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) + propBlockParts, err = propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID = types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} newVss = make([]*validatorStub, nVals+3) copy(newVss, vss[:nVals+3]) @@ -666,7 +674,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin config = sim.Config chain = append([]*types.Block{}, sim.Chain...) // copy chain commits = sim.Commits - store = newMockBlockStore(config, genesisState.ConsensusParams) + store = newMockBlockStore(t, config, genesisState.ConsensusParams) } else { // test single node testConfig := ResetConfig(fmt.Sprintf("%s_%v_s", t.Name(), mode)) defer os.RemoveAll(testConfig.RootDir) @@ -691,7 +699,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin require.NoError(t, err) pubKey, err := privVal.GetPubKey() require.NoError(t, err) - stateDB, genesisState, store = stateAndStore(config, pubKey, kvstore.ProtocolVersion) + stateDB, genesisState, store = stateAndStore(t, config, pubKey, kvstore.ProtocolVersion) } stateStore := sm.NewStore(stateDB) @@ -700,7 +708,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin state := genesisState.Copy() // run the chain through state.ApplyBlock to build up the tendermint state - state = buildTMStateFromChain(config, stateStore, state, chain, nBlocks, mode) + state = buildTMStateFromChain(t, config, stateStore, state, chain, nBlocks, mode) latestAppHash := state.AppHash // make a new client creator @@ -716,7 +724,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin stateStore := sm.NewStore(stateDB1) err := stateStore.Save(genesisState) require.NoError(t, err) - buildAppStateFromChain(proxyApp, stateStore, genesisState, chain, nBlocks, mode) + buildAppStateFromChain(t, proxyApp, stateStore, genesisState, chain, nBlocks, mode) } // Prune block store if requested @@ -776,19 +784,19 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin } } -func applyBlock(stateStore sm.Store, st sm.State, blk *types.Block, proxyApp proxy.AppConns) sm.State { +func applyBlock(t *testing.T, stateStore sm.Store, st sm.State, blk *types.Block, proxyApp proxy.AppConns) sm.State { testPartSize := types.BlockPartSizeBytes blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool) - blkID := types.BlockID{Hash: blk.Hash(), PartSetHeader: blk.MakePartSet(testPartSize).Header()} + bps, err := blk.MakePartSet(testPartSize) + require.NoError(t, err) + blkID := types.BlockID{Hash: blk.Hash(), PartSetHeader: bps.Header()} newState, _, err := blockExec.ApplyBlock(st, blkID, blk) - if err != nil { - panic(err) - } + require.NoError(t, err) return newState } -func buildAppStateFromChain(proxyApp proxy.AppConns, stateStore sm.Store, +func buildAppStateFromChain(t *testing.T, proxyApp proxy.AppConns, stateStore sm.Store, state sm.State, chain []*types.Block, nBlocks int, mode uint) { // start a new app without handshake, play nBlocks blocks if err := proxyApp.Start(); err != nil { @@ -810,18 +818,18 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateStore sm.Store, case 0: for i := 0; i < nBlocks; i++ { block := chain[i] - state = applyBlock(stateStore, state, block, proxyApp) + state = applyBlock(t, stateStore, state, block, proxyApp) } case 1, 2, 3: for i := 0; i < nBlocks-1; i++ { block := chain[i] - state = applyBlock(stateStore, state, block, proxyApp) + state = applyBlock(t, stateStore, state, block, proxyApp) } if mode == 2 || mode == 3 { // update the kvstore height and apphash // as if we ran commit but not - state = applyBlock(stateStore, state, chain[nBlocks-1], proxyApp) + state = applyBlock(t, stateStore, state, chain[nBlocks-1], proxyApp) } default: panic(fmt.Sprintf("unknown mode %v", mode)) @@ -830,6 +838,7 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateStore sm.Store, } func buildTMStateFromChain( + t *testing.T, config *cfg.Config, stateStore sm.Store, state sm.State, @@ -860,19 +869,19 @@ func buildTMStateFromChain( case 0: // sync right up for _, block := range chain { - state = applyBlock(stateStore, state, block, proxyApp) + state = applyBlock(t, stateStore, state, block, proxyApp) } case 1, 2, 3: // sync up to the penultimate as if we stored the block. // whether we commit or not depends on the appHash for _, block := range chain[:len(chain)-1] { - state = applyBlock(stateStore, state, block, proxyApp) + state = applyBlock(t, stateStore, state, block, proxyApp) } // apply the final block to a state copy so we can // get the right next appHash but keep the state back - applyBlock(stateStore, state, chain[len(chain)-1], proxyApp) + applyBlock(t, stateStore, state, chain[len(chain)-1], proxyApp) default: panic(fmt.Sprintf("unknown mode %v", mode)) } @@ -891,12 +900,14 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) { const appVersion = 0x0 pubKey, err := privVal.GetPubKey() require.NoError(t, err) - stateDB, state, store := stateAndStore(config, pubKey, appVersion) + stateDB, state, store := stateAndStore(t, config, pubKey, appVersion) stateStore := sm.NewStore(stateDB) genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile()) state.LastValidators = state.Validators.Copy() // mode = 0 for committing all the blocks - blocks := sf.MakeBlocks(3, &state, privVal) + blocks, err := sf.MakeBlocks(3, &state, privVal) + require.NoError(t, err) + store.chain = blocks // 2. Tendermint must panic if app returns wrong hash for the first block @@ -1099,17 +1110,19 @@ func readPieceFromWAL(msg *TimedWALMessage) interface{} { // fresh state and mock store func stateAndStore( + t *testing.T, config *cfg.Config, pubKey crypto.PubKey, - appVersion uint64) (dbm.DB, sm.State, *mockBlockStore) { + appVersion uint64, +) (dbm.DB, sm.State, *mockBlockStore) { stateDB := dbm.NewMemDB() stateStore := sm.NewStore(stateDB) - state, _ := sm.MakeGenesisStateFromFile(config.GenesisFile()) + state, err := sm.MakeGenesisStateFromFile(config.GenesisFile()) + require.NoError(t, err) state.Version.Consensus.App = appVersion - store := newMockBlockStore(config, state.ConsensusParams) - if err := stateStore.Save(state); err != nil { - panic(err) - } + store := newMockBlockStore(t, config, state.ConsensusParams) + require.NoError(t, stateStore.Save(state)) + return stateDB, state, store } @@ -1122,11 +1135,16 @@ type mockBlockStore struct { chain []*types.Block commits []*types.Commit base int64 + t *testing.T } // TODO: NewBlockStore(db.NewMemDB) ... -func newMockBlockStore(config *cfg.Config, params tmproto.ConsensusParams) *mockBlockStore { - return &mockBlockStore{config, params, nil, nil, 0} +func newMockBlockStore(t *testing.T, config *cfg.Config, params tmproto.ConsensusParams) *mockBlockStore { + return &mockBlockStore{ + config: config, + params: params, + t: t, + } } func (bs *mockBlockStore) Height() int64 { return int64(len(bs.chain)) } @@ -1139,8 +1157,10 @@ func (bs *mockBlockStore) LoadBlockByHash(hash []byte) *types.Block { } func (bs *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta { block := bs.chain[height-1] + bps, err := block.MakePartSet(types.BlockPartSizeBytes) + require.NoError(bs.t, err) return &types.BlockMeta{ - BlockID: types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(types.BlockPartSizeBytes).Header()}, + BlockID: types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}, Header: block.Header, } } @@ -1179,7 +1199,7 @@ func TestHandshakeUpdatesValidators(t *testing.T) { privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()) pubKey, err := privVal.GetPubKey() require.NoError(t, err) - stateDB, state, store := stateAndStore(config, pubKey, 0x0) + stateDB, state, store := stateAndStore(t, config, pubKey, 0x0) stateStore := sm.NewStore(stateDB) oldValAddr := state.Validators.Validators[0].Address diff --git a/consensus/state.go b/consensus/state.go index 83e9de26e..29fb5abca 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -821,7 +821,7 @@ func (cs *State) handleMsg(mi msgInfo) { // We unlock here to yield to any routines that need to read the the RoundState. // Previously, this code held the lock from the point at which the final block - // part was recieved until the block executed against the application. + // part was received until the block executed against the application. // This prevented the reactor from being able to retrieve the most updated // version of the RoundState. The reactor needs the updated RoundState to // gossip the now completed block. @@ -1131,8 +1131,17 @@ func (cs *State) defaultDecideProposal(height int64, round int32) { block, blockParts = cs.ValidBlock, cs.ValidBlockParts } else { // Create a new proposal block from state/txs from the mempool. - block, blockParts = cs.createProposalBlock() - if block == nil { + var err error + block, err = cs.createProposalBlock() + if err != nil { + cs.Logger.Error("unable to create proposal block", "error", err) + return + } else if block == nil { + panic("Method createProposalBlock should not provide a nil block without errors") + } + blockParts, err = block.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + cs.Logger.Error("unable to create proposal block part set", "error", err) return } } @@ -1187,9 +1196,9 @@ func (cs *State) isProposalComplete() bool { // // NOTE: keep it side-effect free for clarity. // CONTRACT: cs.privValidator is not nil. -func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.PartSet) { +func (cs *State) createProposalBlock() (*types.Block, error) { if cs.privValidator == nil { - panic("entered createProposalBlock with privValidator being nil") + return nil, errors.New("entered createProposalBlock with privValidator being nil") } var commit *types.Commit @@ -1204,20 +1213,22 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa commit = cs.LastCommit.MakeCommit() default: // This shouldn't happen. - cs.Logger.Error("propose step; cannot propose anything without commit for the previous block") - return + return nil, errors.New("propose step; cannot propose anything without commit for the previous block") } if cs.privValidatorPubKey == nil { // If this node is a validator & proposer in the current round, it will // miss the opportunity to create a block. - cs.Logger.Error("propose step; empty priv validator public key", "err", errPubKeyIsNotSet) - return + return nil, fmt.Errorf("propose step; empty priv validator public key, error: %w", errPubKeyIsNotSet) } proposerAddr := cs.privValidatorPubKey.Address() - return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr) + ret, err := cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) + if err != nil { + panic(err) + } + return ret, nil } // Enter: `timeoutPropose` after entering Propose. @@ -2059,7 +2070,7 @@ func (cs *State) addVote(vote *types.Vote, peerID p2p.ID) (added bool, err error } // Height mismatch is ignored. - // Not necessarily a bad peer, but not favourable behaviour. + // Not necessarily a bad peer, but not favorable behavior. if vote.Height != cs.Height { cs.Logger.Debug("vote ignored and not added", "vote_height", vote.Height, "cs_height", cs.Height, "peer", peerID) return diff --git a/consensus/state_test.go b/consensus/state_test.go index 1e3887fd9..a551cfd6d 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -191,7 +191,8 @@ func TestStateBadProposal(t *testing.T) { proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) voteCh := subscribe(cs1.eventBus, types.EventQueryVote) - propBlock, _ := cs1.createProposalBlock() // changeProposer(t, cs1, vs2) + propBlock, err := cs1.createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) // make the second validator the proposer by incrementing round round++ @@ -204,7 +205,8 @@ func TestStateBadProposal(t *testing.T) { } stateHash[0] = (stateHash[0] + 1) % 255 propBlock.AppHash = stateHash - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} proposal := types.NewProposal(vs2.Height, round, -1, blockID) p := proposal.ToProto() @@ -230,13 +232,19 @@ func TestStateBadProposal(t *testing.T) { validatePrevote(t, cs1, round, vss[0], nil) // add bad prevote from vs2 and wait for it - signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + bps, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + + signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), bps.Header(), vs2) ensurePrevote(voteCh, height, round) // wait for precommit ensurePrecommit(voteCh, height, round) validatePrecommit(t, cs1, round, -1, vss[0], nil, nil) - signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + + bps2, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), bps2.Header(), vs2) } func TestStateOversizedBlock(t *testing.T) { @@ -250,7 +258,8 @@ func TestStateOversizedBlock(t *testing.T) { timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) voteCh := subscribe(cs1.eventBus, types.EventQueryVote) - propBlock, _ := cs1.createProposalBlock() + propBlock, err := cs1.createProposalBlock() + require.NoError(t, err) propBlock.Data.Txs = []types.Tx{tmrand.Bytes(2001)} propBlock.Header.DataHash = propBlock.Data.Hash() @@ -258,7 +267,8 @@ func TestStateOversizedBlock(t *testing.T) { round++ incrementRound(vss[1:]...) - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} proposal := types.NewProposal(height, round, -1, blockID) p := proposal.ToProto() @@ -290,11 +300,18 @@ func TestStateOversizedBlock(t *testing.T) { // precommit on it ensurePrevote(voteCh, height, round) validatePrevote(t, cs1, round, vss[0], nil) - signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + + bps, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + + signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), bps.Header(), vs2) ensurePrevote(voteCh, height, round) ensurePrecommit(voteCh, height, round) validatePrecommit(t, cs1, round, -1, vss[0], nil, nil) - signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + + bps2, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), bps2.Header(), vs2) } //---------------------------------------------------------------------------------------------------- @@ -466,9 +483,7 @@ func TestStateLockNoPOL(t *testing.T) { rs := cs1.GetRoundState() - if rs.ProposalBlock != nil { - panic("Expected proposal block to be nil") - } + require.Nil(t, rs.ProposalBlock, "Expected proposal block to be nil") // wait to finish prevote ensurePrevote(voteCh, height, round) @@ -476,7 +491,10 @@ func TestStateLockNoPOL(t *testing.T) { validatePrevote(t, cs1, round, vss[0], rs.LockedBlock.Hash()) // add a conflicting prevote from the other validator - signAddVotes(cs1, tmproto.PrevoteType, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2) + bps, err := rs.LockedBlock.MakePartSet(partSize) + require.NoError(t, err) + + signAddVotes(cs1, tmproto.PrevoteType, hash, bps.Header(), vs2) ensurePrevote(voteCh, height, round) // now we're going to enter prevote again, but with invalid args @@ -489,7 +507,9 @@ func TestStateLockNoPOL(t *testing.T) { validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // add conflicting precommit from vs2 - signAddVotes(cs1, tmproto.PrecommitType, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2) + bps2, err := rs.LockedBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrecommitType, hash, bps2.Header(), vs2) ensurePrecommit(voteCh, height, round) // (note we're entering precommit for a second time this round, but with invalid args @@ -519,7 +539,9 @@ func TestStateLockNoPOL(t *testing.T) { ensurePrevote(voteCh, height, round) // prevote validatePrevote(t, cs1, round, vss[0], rs.LockedBlock.Hash()) - signAddVotes(cs1, tmproto.PrevoteType, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2) + bps0, err := rs.ProposalBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrevoteType, hash, bps0.Header(), vs2) ensurePrevote(voteCh, height, round) ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds()) @@ -527,11 +549,13 @@ func TestStateLockNoPOL(t *testing.T) { validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // precommit nil but be locked on proposal + bps1, err := rs.ProposalBlock.MakePartSet(partSize) + require.NoError(t, err) signAddVotes( cs1, tmproto.PrecommitType, hash, - rs.ProposalBlock.MakePartSet(partSize).Header(), + bps1.Header(), vs2) // NOTE: conflicting precommits at same height ensurePrecommit(voteCh, height, round) @@ -539,7 +563,7 @@ func TestStateLockNoPOL(t *testing.T) { cs2, _ := randState(2) // needed so generated block is different than locked block // before we time out into new round, set next proposal block - prop, propBlock := decideProposal(cs2, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs2, vs2, vs2.Height, vs2.Round+1) if prop == nil || propBlock == nil { t.Fatal("Failed to create proposal block with vs2") } @@ -555,7 +579,9 @@ func TestStateLockNoPOL(t *testing.T) { // now we're on a new round and not the proposer // so set the proposal block - if err := cs1.SetProposalAndBlock(prop, propBlock, propBlock.MakePartSet(partSize), ""); err != nil { + bps3, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + if err := cs1.SetProposalAndBlock(prop, propBlock, bps3, ""); err != nil { t.Fatal(err) } @@ -565,18 +591,23 @@ func TestStateLockNoPOL(t *testing.T) { validatePrevote(t, cs1, 3, vss[0], cs1.LockedBlock.Hash()) // prevote for proposed block - signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + bps4, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + + signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), bps4.Header(), vs2) ensurePrevote(voteCh, height, round) ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds()) ensurePrecommit(voteCh, height, round) validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // precommit nil but locked on proposal + bps5, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) signAddVotes( cs1, tmproto.PrecommitType, propBlock.Hash(), - propBlock.MakePartSet(partSize).Header(), + bps5.Header(), vs2) // NOTE: conflicting precommits at same height ensurePrecommit(voteCh, height, round) } @@ -631,11 +662,13 @@ func TestStateLockPOLRelock(t *testing.T) { // before we timeout to the new round set the new proposal cs2 := newState(cs1.state, vs2, counter.NewApplication(true)) - prop, propBlock := decideProposal(cs2, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs2, vs2, vs2.Height, vs2.Round+1) if prop == nil || propBlock == nil { t.Fatal("Failed to create proposal block with vs2") } - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + propBlockHash := propBlock.Hash() require.NotEqual(t, propBlockHash, theBlockHash) @@ -728,8 +761,9 @@ func TestStateLockPOLUnlock(t *testing.T) { signAddVotes(cs1, tmproto.PrecommitType, theBlockHash, theBlockParts, vs3) // before we time out into new round, set next proposal block - prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1) - propBlockParts := propBlock.MakePartSet(partSize) + prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round+1) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) // timeout to new round ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds()) @@ -816,11 +850,13 @@ func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) { // before we timeout to the new round set the new proposal cs2 := newState(cs1.state, vs2, counter.NewApplication(true)) - prop, propBlock := decideProposal(cs2, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs2, vs2, vs2.Height, vs2.Round+1) if prop == nil || propBlock == nil { t.Fatal("Failed to create proposal block with vs2") } - secondBlockParts := propBlock.MakePartSet(partSize) + secondBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + secondBlockHash := propBlock.Hash() require.NotEqual(t, secondBlockHash, firstBlockHash) @@ -860,11 +896,12 @@ func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) { // before we timeout to the new round set the new proposal cs3 := newState(cs1.state, vs3, counter.NewApplication(true)) - prop, propBlock = decideProposal(cs3, vs3, vs3.Height, vs3.Round+1) + prop, propBlock = decideProposal(t, cs3, vs3, vs3.Height, vs3.Round+1) if prop == nil || propBlock == nil { t.Fatal("Failed to create proposal block with vs2") } - thirdPropBlockParts := propBlock.MakePartSet(partSize) + thirdPropBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) thirdPropBlockHash := propBlock.Hash() require.NotEqual(t, secondBlockHash, thirdPropBlockHash) @@ -928,7 +965,10 @@ func TestStateLockPOLSafety1(t *testing.T) { validatePrevote(t, cs1, round, vss[0], propBlock.Hash()) // the others sign a polka but we don't see it - prevotes := signVotes(tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4) + bps, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + + prevotes := signVotes(tmproto.PrevoteType, propBlock.Hash(), bps.Header(), vs2, vs3, vs4) t.Logf("old prop hash %v", fmt.Sprintf("%X", propBlock.Hash())) @@ -941,9 +981,10 @@ func TestStateLockPOLSafety1(t *testing.T) { t.Log("### ONTO ROUND 1") - prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round+1) propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) incrementRound(vs2, vs3, vs4) @@ -1037,18 +1078,20 @@ func TestStateLockPOLSafety2(t *testing.T) { // the block for R0: gets polkad but we miss it // (even though we signed it, shhh) - _, propBlock0 := decideProposal(cs1, vss[0], height, round) + _, propBlock0 := decideProposal(t, cs1, vss[0], height, round) propBlockHash0 := propBlock0.Hash() - propBlockParts0 := propBlock0.MakePartSet(partSize) + propBlockParts0, err := propBlock0.MakePartSet(partSize) + require.NoError(t, err) propBlockID0 := types.BlockID{Hash: propBlockHash0, PartSetHeader: propBlockParts0.Header()} // the others sign a polka but we don't see it prevotes := signVotes(tmproto.PrevoteType, propBlockHash0, propBlockParts0.Header(), vs2, vs3, vs4) // the block for round 1 - prop1, propBlock1 := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1) + prop1, propBlock1 := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round+1) propBlockHash1 := propBlock1.Hash() - propBlockParts1 := propBlock1.MakePartSet(partSize) + propBlockParts1, err := propBlock1.MakePartSet(partSize) + require.NoError(t, err) incrementRound(vs2, vs3, vs4) @@ -1146,7 +1189,9 @@ func TestProposeValidBlock(t *testing.T) { validatePrevote(t, cs1, round, vss[0], propBlockHash) // the others sign a polka - signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4) + bps, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, bps.Header(), vs2, vs3, vs4) ensurePrecommit(voteCh, height, round) // we should have precommitted @@ -1230,7 +1275,8 @@ func TestSetValidBlockOnDelayedPrevote(t *testing.T) { rs := cs1.GetRoundState() propBlock := rs.ProposalBlock propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) ensurePrevote(voteCh, height, round) validatePrevote(t, cs1, round, vss[0], propBlockHash) @@ -1296,9 +1342,10 @@ func TestSetValidBlockOnDelayedProposal(t *testing.T) { ensurePrevote(voteCh, height, round) validatePrevote(t, cs1, round, vss[0], nil) - prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round+1) propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) // vs2, vs3 and vs4 send prevote for propBlock signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4) @@ -1456,9 +1503,10 @@ func TestEmitNewValidBlockEventOnCommitWithoutBlock(t *testing.T) { newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock) - _, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round) + _, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round) propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) // start round in which PO is not proposer startTestRound(cs1, height, round) @@ -1489,9 +1537,10 @@ func TestCommitFromPreviousRound(t *testing.T) { validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock) proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) - prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round) + prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round) propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) // start round in which PO is not proposer startTestRound(cs1, height, round) @@ -1634,8 +1683,9 @@ func TestResetTimeoutPrecommitUponNewHeight(t *testing.T) { ensureNewBlockHeader(newBlockHeader, height, theBlockHash) - prop, propBlock := decideProposal(cs1, vs2, height+1, 0) - propBlockParts := propBlock.MakePartSet(partSize) + prop, propBlock := decideProposal(t, cs1, vs2, height+1, 0) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil { t.Fatal(err) @@ -1756,7 +1806,8 @@ func TestStateHalt1(t *testing.T) { ensureNewProposal(proposalCh, height, round) rs := cs1.GetRoundState() propBlock := rs.ProposalBlock - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) ensurePrevote(voteCh, height, round) diff --git a/docker-compose.yml b/docker-compose.yml index ccc802040..647e1f202 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -63,6 +63,4 @@ networks: ipam: driver: default config: - - - subnet: 192.167.10.0/16 - + - subnet: 192.167.10.0/16 diff --git a/evidence/pool_test.go b/evidence/pool_test.go index 106fa8aa5..f0fba1ac2 100644 --- a/evidence/pool_test.go +++ b/evidence/pool_test.go @@ -148,7 +148,7 @@ func TestAddExpiredEvidence(t *testing.T) { func TestReportConflictingVotes(t *testing.T) { var height int64 = 10 - pool, pv := defaultTestPool(height) + pool, pv := defaultTestPool(t, height) val := types.NewValidator(pv.PrivKey.PubKey(), 10) ev := types.NewMockDuplicateVoteEvidenceWithValidator(height+1, defaultEvidenceTime, pv, evidenceChainID) @@ -182,7 +182,7 @@ func TestReportConflictingVotes(t *testing.T) { func TestEvidencePoolUpdate(t *testing.T) { height := int64(21) - pool, val := defaultTestPool(height) + pool, val := defaultTestPool(t, height) state := pool.State() // create new block (no need to save it to blockStore) @@ -215,7 +215,7 @@ func TestEvidencePoolUpdate(t *testing.T) { func TestVerifyPendingEvidencePasses(t *testing.T) { var height int64 = 1 - pool, val := defaultTestPool(height) + pool, val := defaultTestPool(t, height) ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(1*time.Minute), val, evidenceChainID) err := pool.AddEvidence(ev) @@ -227,7 +227,7 @@ func TestVerifyPendingEvidencePasses(t *testing.T) { func TestVerifyDuplicatedEvidenceFails(t *testing.T) { var height int64 = 1 - pool, val := defaultTestPool(height) + pool, val := defaultTestPool(t, height) ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(1*time.Minute), val, evidenceChainID) err := pool.CheckEvidence(types.EvidenceList{ev, ev}) @@ -307,7 +307,8 @@ func TestRecoverPendingEvidence(t *testing.T) { stateStore := initializeValidatorState(val, height) state, err := stateStore.Load() require.NoError(t, err) - blockStore := initializeBlockStore(dbm.NewMemDB(), state, valAddress) + blockStore, err := initializeBlockStore(dbm.NewMemDB(), state, valAddress) + require.NoError(t, err) // create previous pool and populate it pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore) require.NoError(t, err) @@ -399,7 +400,7 @@ func initializeValidatorState(privVal types.PrivValidator, height int64) sm.Stor // initializeBlockStore creates a block storage and populates it w/ a dummy // block at +height+. -func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) *store.BlockStore { +func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) (*store.BlockStore, error) { blockStore := store.NewBlockStore(db) for i := int64(1); i <= state.LastBlockHeight; i++ { @@ -408,13 +409,16 @@ func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) *store.Bloc block.Header.Time = defaultEvidenceTime.Add(time.Duration(i) * time.Minute) block.Header.Version = tmversion.Consensus{Block: version.BlockProtocol, App: 1} const parts = 1 - partSet := block.MakePartSet(parts) + partSet, err := block.MakePartSet(parts) + if err != nil { + return nil, err + } seenCommit := makeCommit(i, valAddr) blockStore.SaveBlock(block, partSet, seenCommit) } - return blockStore + return blockStore, nil } func makeCommit(height int64, valAddr []byte) *types.Commit { @@ -427,13 +431,15 @@ func makeCommit(height int64, valAddr []byte) *types.Commit { return types.NewCommit(height, 0, types.BlockID{}, commitSigs) } -func defaultTestPool(height int64) (*evidence.Pool, types.MockPV) { +func defaultTestPool(t *testing.T, height int64) (*evidence.Pool, types.MockPV) { + t.Helper() val := types.NewMockPV() valAddress := val.PrivKey.PubKey().Address() evidenceDB := dbm.NewMemDB() stateStore := initializeValidatorState(val, height) state, _ := stateStore.Load() - blockStore := initializeBlockStore(dbm.NewMemDB(), state, valAddress) + blockStore, err := initializeBlockStore(dbm.NewMemDB(), state, valAddress) + require.NoError(t, err) pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore) if err != nil { panic("test evidence pool could not be created") diff --git a/libs/pubsub/pubsub.go b/libs/pubsub/pubsub.go index 914a080de..4ea876e9e 100644 --- a/libs/pubsub/pubsub.go +++ b/libs/pubsub/pubsub.go @@ -27,7 +27,7 @@ // select { // case msg <- subscription.Out(): // // handle msg.Data() and msg.Events() -// case <-subscription.Cancelled(): +// case <-subscription.Canceled(): // return subscription.Err() // } // } diff --git a/libs/pubsub/subscription.go b/libs/pubsub/subscription.go index 8f90e177a..f1082bbbc 100644 --- a/libs/pubsub/subscription.go +++ b/libs/pubsub/subscription.go @@ -46,7 +46,7 @@ func (s *Subscription) Out() <-chan Message { // nolint: misspell // Cancelled returns a channel that's closed when the subscription is // terminated and supposed to be used in a select statement. -func (s *Subscription) Cancelled() <-chan struct{} { +func (s *Subscription) Cancelled() <-chan struct{} { // nolint: misspell return s.canceled } diff --git a/light/provider/http/http.go b/light/provider/http/http.go index 665fcbe70..dcf1b0d10 100644 --- a/light/provider/http/http.go +++ b/light/provider/http/http.go @@ -193,7 +193,7 @@ func (p *http) signedHeader(ctx context.Context, height *int64) (*types.SignedHe time.Sleep(backoffTimeout(uint16(attempt))) continue - // either context was cancelled or connection refused. + // either context was canceled or connection refused. default: return nil, err } diff --git a/mempool/mempool.go b/mempool/mempool.go index 08717fd95..f776fbc9b 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -23,6 +23,8 @@ const ( MaxActiveIDs = math.MaxUint16 ) +//go:generate mockery --case underscore --name Mempool + // Mempool defines the mempool interface. // // Updates to the mempool need to be synchronized with committing a block so diff --git a/mempool/mock/mempool.go b/mempool/mock/mempool.go deleted file mode 100644 index 3f293381f..000000000 --- a/mempool/mock/mempool.go +++ /dev/null @@ -1,43 +0,0 @@ -package mock - -import ( - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/clist" - "github.com/tendermint/tendermint/mempool" - "github.com/tendermint/tendermint/types" -) - -// Mempool is an empty implementation of a Mempool, useful for testing. -type Mempool struct{} - -var _ mempool.Mempool = Mempool{} - -func (Mempool) Lock() {} -func (Mempool) Unlock() {} -func (Mempool) Size() int { return 0 } -func (Mempool) CheckTx(_ types.Tx, _ func(*abci.Response), _ mempool.TxInfo) error { - return nil -} -func (Mempool) RemoveTxByKey(txKey types.TxKey) error { return nil } -func (Mempool) ReapMaxBytesMaxGas(_, _ int64) types.Txs { return types.Txs{} } -func (Mempool) ReapMaxTxs(n int) types.Txs { return types.Txs{} } -func (Mempool) Update( - _ int64, - _ types.Txs, - _ []*abci.ResponseDeliverTx, - _ mempool.PreCheckFunc, - _ mempool.PostCheckFunc, -) error { - return nil -} -func (Mempool) Flush() {} -func (Mempool) FlushAppConn() error { return nil } -func (Mempool) TxsAvailable() <-chan struct{} { return make(chan struct{}) } -func (Mempool) EnableTxsAvailable() {} -func (Mempool) SizeBytes() int64 { return 0 } - -func (Mempool) TxsFront() *clist.CElement { return nil } -func (Mempool) TxsWaitChan() <-chan struct{} { return nil } - -func (Mempool) InitWAL() error { return nil } -func (Mempool) CloseWAL() {} diff --git a/mempool/mocks/mempool.go b/mempool/mocks/mempool.go new file mode 100644 index 000000000..94c024ac2 --- /dev/null +++ b/mempool/mocks/mempool.go @@ -0,0 +1,184 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import ( + abcitypes "github.com/tendermint/tendermint/abci/types" + mempool "github.com/tendermint/tendermint/mempool" + + mock "github.com/stretchr/testify/mock" + + types "github.com/tendermint/tendermint/types" +) + +// Mempool is an autogenerated mock type for the Mempool type +type Mempool struct { + mock.Mock +} + +// CheckTx provides a mock function with given fields: tx, callback, txInfo +func (_m *Mempool) CheckTx(tx types.Tx, callback func(*abcitypes.Response), txInfo mempool.TxInfo) error { + ret := _m.Called(tx, callback, txInfo) + + var r0 error + if rf, ok := ret.Get(0).(func(types.Tx, func(*abcitypes.Response), mempool.TxInfo) error); ok { + r0 = rf(tx, callback, txInfo) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// EnableTxsAvailable provides a mock function with given fields: +func (_m *Mempool) EnableTxsAvailable() { + _m.Called() +} + +// Flush provides a mock function with given fields: +func (_m *Mempool) Flush() { + _m.Called() +} + +// FlushAppConn provides a mock function with given fields: +func (_m *Mempool) FlushAppConn() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Lock provides a mock function with given fields: +func (_m *Mempool) Lock() { + _m.Called() +} + +// ReapMaxBytesMaxGas provides a mock function with given fields: maxBytes, maxGas +func (_m *Mempool) ReapMaxBytesMaxGas(maxBytes int64, maxGas int64) types.Txs { + ret := _m.Called(maxBytes, maxGas) + + var r0 types.Txs + if rf, ok := ret.Get(0).(func(int64, int64) types.Txs); ok { + r0 = rf(maxBytes, maxGas) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Txs) + } + } + + return r0 +} + +// ReapMaxTxs provides a mock function with given fields: max +func (_m *Mempool) ReapMaxTxs(max int) types.Txs { + ret := _m.Called(max) + + var r0 types.Txs + if rf, ok := ret.Get(0).(func(int) types.Txs); ok { + r0 = rf(max) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Txs) + } + } + + return r0 +} + +// RemoveTxByKey provides a mock function with given fields: txKey +func (_m *Mempool) RemoveTxByKey(txKey types.TxKey) error { + ret := _m.Called(txKey) + + var r0 error + if rf, ok := ret.Get(0).(func(types.TxKey) error); ok { + r0 = rf(txKey) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Size provides a mock function with given fields: +func (_m *Mempool) Size() int { + ret := _m.Called() + + var r0 int + if rf, ok := ret.Get(0).(func() int); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int) + } + + return r0 +} + +// SizeBytes provides a mock function with given fields: +func (_m *Mempool) SizeBytes() int64 { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + return r0 +} + +// TxsAvailable provides a mock function with given fields: +func (_m *Mempool) TxsAvailable() <-chan struct{} { + ret := _m.Called() + + var r0 <-chan struct{} + if rf, ok := ret.Get(0).(func() <-chan struct{}); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan struct{}) + } + } + + return r0 +} + +// Unlock provides a mock function with given fields: +func (_m *Mempool) Unlock() { + _m.Called() +} + +// Update provides a mock function with given fields: blockHeight, blockTxs, deliverTxResponses, newPreFn, newPostFn +func (_m *Mempool) Update(blockHeight int64, blockTxs types.Txs, deliverTxResponses []*abcitypes.ResponseDeliverTx, newPreFn mempool.PreCheckFunc, newPostFn mempool.PostCheckFunc) error { + ret := _m.Called(blockHeight, blockTxs, deliverTxResponses, newPreFn, newPostFn) + + var r0 error + if rf, ok := ret.Get(0).(func(int64, types.Txs, []*abcitypes.ResponseDeliverTx, mempool.PreCheckFunc, mempool.PostCheckFunc) error); ok { + r0 = rf(blockHeight, blockTxs, deliverTxResponses, newPreFn, newPostFn) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewMempool interface { + mock.TestingT + Cleanup(func()) +} + +// NewMempool creates a new instance of Mempool. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMempool(t mockConstructorTestingTNewMempool) *Mempool { + mock := &Mempool{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/networks/remote/ansible/config.yml b/networks/remote/ansible/config.yml index 7b772fb70..6b88cb3c2 100644 --- a/networks/remote/ansible/config.yml +++ b/networks/remote/ansible/config.yml @@ -15,4 +15,3 @@ - config - unsafe_reset - start - diff --git a/networks/remote/ansible/install.yml b/networks/remote/ansible/install.yml index a57b4be44..9c191a938 100644 --- a/networks/remote/ansible/install.yml +++ b/networks/remote/ansible/install.yml @@ -8,4 +8,3 @@ - service: tendermint roles: - install - diff --git a/networks/remote/ansible/logzio.yml b/networks/remote/ansible/logzio.yml index 53f637f2f..3ce04988b 100644 --- a/networks/remote/ansible/logzio.yml +++ b/networks/remote/ansible/logzio.yml @@ -11,4 +11,3 @@ - JOURNALBEAT_BINARY: "{{lookup('env', 'GOPATH')}}/bin/journalbeat" roles: - logzio - diff --git a/networks/remote/ansible/reset.yml b/networks/remote/ansible/reset.yml index 63b1733c7..3c6e091c3 100644 --- a/networks/remote/ansible/reset.yml +++ b/networks/remote/ansible/reset.yml @@ -10,5 +10,3 @@ - stop - unsafe_reset - start - - diff --git a/networks/remote/ansible/restart.yml b/networks/remote/ansible/restart.yml index 71d4bc66d..ff98d03a6 100644 --- a/networks/remote/ansible/restart.yml +++ b/networks/remote/ansible/restart.yml @@ -9,4 +9,3 @@ roles: - stop - start - diff --git a/networks/remote/ansible/roles/config/tasks/main.yml b/networks/remote/ansible/roles/config/tasks/main.yml index a51098caa..b7d9b8edb 100644 --- a/networks/remote/ansible/roles/config/tasks/main.yml +++ b/networks/remote/ansible/roles/config/tasks/main.yml @@ -13,5 +13,4 @@ dest: "/home/{{service}}/.{{service}}/" owner: "{{service}}" group: "{{service}}" - loop: [ 0, 1, 2, 3, 4, 5, 6, 7 ] - + loop: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/networks/remote/ansible/roles/install/handlers/main.yml b/networks/remote/ansible/roles/install/handlers/main.yml index 16afbb618..689f5d82f 100644 --- a/networks/remote/ansible/roles/install/handlers/main.yml +++ b/networks/remote/ansible/roles/install/handlers/main.yml @@ -2,4 +2,3 @@ - name: reload services systemd: "name={{service}} daemon_reload=yes enabled=yes" - diff --git a/networks/remote/ansible/roles/install/tasks/main.yml b/networks/remote/ansible/roles/install/tasks/main.yml index 9e5a7524a..8b631769b 100644 --- a/networks/remote/ansible/roles/install/tasks/main.yml +++ b/networks/remote/ansible/roles/install/tasks/main.yml @@ -12,4 +12,3 @@ - name: Create service template: "src=systemd.service.j2 dest=/etc/systemd/system/{{service}}.service" notify: reload services - diff --git a/networks/remote/ansible/roles/logzio/handlers/main.yml b/networks/remote/ansible/roles/logzio/handlers/main.yml index 0b371fc51..f2a916b9a 100644 --- a/networks/remote/ansible/roles/logzio/handlers/main.yml +++ b/networks/remote/ansible/roles/logzio/handlers/main.yml @@ -5,4 +5,3 @@ - name: restart journalbeat service: name=journalbeat state=restarted - diff --git a/networks/remote/ansible/roles/logzio/tasks/main.yml b/networks/remote/ansible/roles/logzio/tasks/main.yml index ab3976f22..5131d98ac 100644 --- a/networks/remote/ansible/roles/logzio/tasks/main.yml +++ b/networks/remote/ansible/roles/logzio/tasks/main.yml @@ -24,4 +24,3 @@ notify: - reload daemon - restart journalbeat - diff --git a/networks/remote/ansible/roles/start/tasks/main.yml b/networks/remote/ansible/roles/start/tasks/main.yml index 6bc611c91..68b41f71f 100644 --- a/networks/remote/ansible/roles/start/tasks/main.yml +++ b/networks/remote/ansible/roles/start/tasks/main.yml @@ -2,4 +2,3 @@ - name: start service service: "name={{service}} state=started" - diff --git a/networks/remote/ansible/roles/status/tasks/main.yml b/networks/remote/ansible/roles/status/tasks/main.yml index 50170c746..4b6ac5ee6 100644 --- a/networks/remote/ansible/roles/status/tasks/main.yml +++ b/networks/remote/ansible/roles/status/tasks/main.yml @@ -7,4 +7,3 @@ - name: Result debug: var=status.stdout_lines - diff --git a/networks/remote/ansible/roles/stop/tasks/main.yml b/networks/remote/ansible/roles/stop/tasks/main.yml index 7db356f22..b32b0cea1 100644 --- a/networks/remote/ansible/roles/stop/tasks/main.yml +++ b/networks/remote/ansible/roles/stop/tasks/main.yml @@ -2,4 +2,3 @@ - name: stop service service: "name={{service}} state=stopped" - diff --git a/networks/remote/ansible/roles/unsafe_reset/tasks/main.yml b/networks/remote/ansible/roles/unsafe_reset/tasks/main.yml index 6ac1ec55a..59ae68d17 100644 --- a/networks/remote/ansible/roles/unsafe_reset/tasks/main.yml +++ b/networks/remote/ansible/roles/unsafe_reset/tasks/main.yml @@ -1,4 +1,3 @@ - command: "{{service}} unsafe_reset_all {{ (service != 'tendermint') | ternary('node','') }} --home /home/{{service}}/.{{service}}" become_user: "{{service}}" become: yes - diff --git a/networks/remote/ansible/start.yml b/networks/remote/ansible/start.yml index 2be07dc73..cc575de7a 100644 --- a/networks/remote/ansible/start.yml +++ b/networks/remote/ansible/start.yml @@ -8,4 +8,3 @@ - service: tendermint roles: - start - diff --git a/networks/remote/ansible/status.yml b/networks/remote/ansible/status.yml index a1721b87b..4a31be689 100644 --- a/networks/remote/ansible/status.yml +++ b/networks/remote/ansible/status.yml @@ -8,4 +8,3 @@ - service: tendermint roles: - status - diff --git a/networks/remote/ansible/stop.yml b/networks/remote/ansible/stop.yml index abc6031d5..e9e75c386 100644 --- a/networks/remote/ansible/stop.yml +++ b/networks/remote/ansible/stop.yml @@ -8,4 +8,3 @@ - service: tendermint roles: - stop - diff --git a/node/node_test.go b/node/node_test.go index 9b82d6ca2..5382c94df 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -52,7 +52,7 @@ func TestNodeStartStop(t *testing.T) { select { case <-blocksSub.Out(): case <-blocksSub.Cancelled(): - t.Fatal("blocksSub was cancelled") + t.Fatal("blocksSub was canceled") case <-time.After(10 * time.Second): t.Fatal("timed out waiting for the node to produce a block") } @@ -305,14 +305,17 @@ func TestCreateProposalBlock(t *testing.T) { ) commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) - block, _ := blockExec.CreateProposalBlock( + block, err := blockExec.CreateProposalBlock( height, state, commit, proposerAddr, + nil, ) + require.NoError(t, err) // check that the part set does not exceed the maximum block size - partSet := block.MakePartSet(partSize) + partSet, err := block.MakePartSet(partSize) + require.NoError(t, err) assert.Less(t, partSet.ByteSize(), int64(maxBytes)) partSetFromHeader := types.NewPartSetFromHeader(partSet.Header()) @@ -383,18 +386,21 @@ func TestMaxProposalBlockSize(t *testing.T) { ) commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) - block, _ := blockExec.CreateProposalBlock( + block, err := blockExec.CreateProposalBlock( height, state, commit, proposerAddr, + nil, ) + require.NoError(t, err) pb, err := block.ToProto() require.NoError(t, err) assert.Less(t, int64(pb.Size()), maxBytes) // check that the part set does not exceed the maximum block size - partSet := block.MakePartSet(partSize) + partSet, err := block.MakePartSet(partSize) + require.NoError(t, err) assert.EqualValues(t, partSet.ByteSize(), int64(pb.Size())) } diff --git a/p2p/netaddress.go b/p2p/netaddress.go index b42d325c8..e3daa1a87 100644 --- a/p2p/netaddress.go +++ b/p2p/netaddress.go @@ -329,7 +329,7 @@ func (na *NetAddress) ReachabilityTo(o *NetAddress) int { case o.IP.To4() != nil: return Ipv4 case tunneled: - // only prioritise ipv6 if we aren't tunnelling it. + // only prioritize ipv6 if we aren't tunneling it. return Ipv6Weak } return Ipv6Strong diff --git a/p2p/pex/addrbook_test.go b/p2p/pex/addrbook_test.go index ad41d5562..c04ad9c3a 100644 --- a/p2p/pex/addrbook_test.go +++ b/p2p/pex/addrbook_test.go @@ -771,7 +771,7 @@ func countOldAndNewAddrsInSelection(addrs []*p2p.NetAddress, book *addrBook) (nO return } -// Analyse the layout of the selection specified by 'addrs' +// Analyze the layout of the selection specified by 'addrs' // Returns: // - seqLens - the lengths of the sequences of addresses of same type // - seqTypes - the types of sequences in selection diff --git a/p2p/pex/pex_reactor.go b/p2p/pex/pex_reactor.go index a13e3170e..0c3ba218d 100644 --- a/p2p/pex/pex_reactor.go +++ b/p2p/pex/pex_reactor.go @@ -489,7 +489,7 @@ func (r *Reactor) ensurePeers() { } // TODO: consider moving some checks from toDial into here // so we don't even consider dialing peers that we want to wait - // before dialling again, or have dialed too many times already + // before dialing again, or have dialed too many times already toDial[try.ID] = try } diff --git a/p2p/transport.go b/p2p/transport.go index 1257f38b3..e6e19a901 100644 --- a/p2p/transport.go +++ b/p2p/transport.go @@ -20,7 +20,7 @@ const ( defaultHandshakeTimeout = 3 * time.Second ) -// IPResolver is a behaviour subset of net.Resolver. +// IPResolver is a behavior subset of net.Resolver. type IPResolver interface { LookupIPAddr(context.Context, string) ([]net.IPAddr, error) } @@ -70,7 +70,7 @@ type Transport interface { } // transportLifecycle bundles the methods for callers to control start and stop -// behaviour. +// behavior. type transportLifecycle interface { Close() error Listen(NetAddress) error diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 26cadcb3d..bd9724dfb 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -127,12 +127,15 @@ message RequestApplySnapshotChunk { } message RequestPrepareProposal { - // block_data is an array of transactions that will be included in a block, + bytes hash = 1; + tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; + // txs is an array of transactions that will be included in a block, // sent to the app for possible modifications. - // applications can not exceed the size of the data passed to it. - repeated bytes block_data = 1; - // If an application decides to populate block_data with extra information, they can not exceed this value. - int64 block_data_size = 2; + repeated bytes txs = 3; + ExtendedCommitInfo local_last_commit = 4 [(gogoproto.nullable) = false]; + repeated Evidence byzantine_validators = 5 [(gogoproto.nullable) = false]; + // the modified transactions cannot exceed this size. + int64 max_tx_bytes = 6; } message RequestProcessProposal { @@ -309,7 +312,7 @@ message ResponseApplySnapshotChunk { } message ResponsePrepareProposal { - repeated bytes block_data = 1; + repeated TxRecord tx_records = 1; } message ResponseProcessProposal { @@ -347,6 +350,11 @@ message CommitInfo { repeated VoteInfo votes = 2 [(gogoproto.nullable) = false]; } +message ExtendedCommitInfo { + int32 round = 1; + repeated ExtendedVoteInfo votes = 2 [(gogoproto.nullable) = false]; +} + // Event allows application developers to attach additional information to // ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. // Later, transactions may be queried using these events. @@ -375,6 +383,19 @@ message TxResult { ResponseDeliverTx result = 4 [(gogoproto.nullable) = false]; } +message TxRecord { + TxAction action = 1; + bytes tx = 2; + + // TxAction contains App-provided information on what to do with a transaction that is part of a raw proposal + enum TxAction { + UNKNOWN = 0; // Unknown action + UNMODIFIED = 1; // The Application did not modify this transaction. + ADDED = 2; // The Application added this transaction. + REMOVED = 3; // The Application wants this transaction removed from the proposal and the mempool. + } +} + //---------------------------------------- // Blockchain Types @@ -395,6 +416,14 @@ message ValidatorUpdate { message VoteInfo { Validator validator = 1 [(gogoproto.nullable) = false]; bool signed_last_block = 2; + reserved 3; // Placeholder for tendermint_signed_extension in v0.37 + reserved 4; // Placeholder for app_signed_extension in v0.37 +} + +message ExtendedVoteInfo { + Validator validator = 1 [(gogoproto.nullable) = false]; + bool signed_last_block = 2; + bytes vote_extension = 3; // Reserved for future use } enum EvidenceType { diff --git a/proxy/client.go b/proxy/client.go index e78e827ab..08887f4d1 100644 --- a/proxy/client.go +++ b/proxy/client.go @@ -11,6 +11,8 @@ import ( e2e "github.com/tendermint/tendermint/test/e2e/app" ) +//go:generate mockery --case underscore --name ClientCreator + // ClientCreator creates new ABCI clients. type ClientCreator interface { // NewABCIClient returns a new ABCI client. diff --git a/proxy/mocks/client_creator.go b/proxy/mocks/client_creator.go index e4b924ab5..dd757f97b 100644 --- a/proxy/mocks/client_creator.go +++ b/proxy/mocks/client_creator.go @@ -1,10 +1,9 @@ -// Code generated by mockery v1.1.1. DO NOT EDIT. +// Code generated by mockery v2.14.0. DO NOT EDIT. package mocks import ( mock "github.com/stretchr/testify/mock" - abcicli "github.com/tendermint/tendermint/abci/client" ) @@ -35,3 +34,18 @@ func (_m *ClientCreator) NewABCIClient() (abcicli.Client, error) { return r0, r1 } + +type mockConstructorTestingTNewClientCreator interface { + mock.TestingT + Cleanup(func()) +} + +// NewClientCreator creates a new instance of ClientCreator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewClientCreator(t mockConstructorTestingTNewClientCreator) *ClientCreator { + mock := &ClientCreator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/rpc/client/helpers.go b/rpc/client/helpers.go index 0878df6a8..8014d875a 100644 --- a/rpc/client/helpers.go +++ b/rpc/client/helpers.go @@ -70,7 +70,7 @@ func WaitForOneEvent(c EventsClient, evtTyp string, timeout time.Duration) (type // make sure to unregister after the test is over defer func() { if deferErr := c.UnsubscribeAll(ctx, subscriber); deferErr != nil { - panic(err) + panic(deferErr) } }() diff --git a/rpc/client/interface.go b/rpc/client/interface.go index cda5c541c..36dc2f7d1 100644 --- a/rpc/client/interface.go +++ b/rpc/client/interface.go @@ -138,7 +138,7 @@ type MempoolClient interface { } // EvidenceClient is used for submitting an evidence of the malicious -// behaviour. +// behavior. type EvidenceClient interface { BroadcastEvidence(context.Context, types.Evidence) (*ctypes.ResultBroadcastEvidence, error) } diff --git a/rpc/client/local/local.go b/rpc/client/local/local.go index 62c8415a7..d0dfc3723 100644 --- a/rpc/client/local/local.go +++ b/rpc/client/local/local.go @@ -259,7 +259,7 @@ func (c *Local) eventsRoutine( return } - c.Logger.Error("subscription was cancelled, resubscribing...", "err", sub.Err(), "query", q.String()) + c.Logger.Error("subscription was canceled, resubscribing...", "err", sub.Err(), "query", q.String()) sub = c.resubscribe(subscriber, q) if sub == nil { // client was stopped return diff --git a/rpc/core/events.go b/rpc/core/events.go index ae4577650..1b4e6d778 100644 --- a/rpc/core/events.go +++ b/rpc/core/events.go @@ -66,7 +66,7 @@ func Subscribe(ctx *rpctypes.Context, query string) (*ctypes.ResultSubscribe, er if closeIfSlow { var ( - err = errors.New("subscription was cancelled (reason: slow client)") + err = errors.New("subscription was canceled (reason: slow client)") resp = rpctypes.RPCServerError(subscriptionID, err) ) if !ctx.WSConn.TryWriteRPCResponse(resp) { @@ -85,7 +85,7 @@ func Subscribe(ctx *rpctypes.Context, query string) (*ctypes.ResultSubscribe, er reason = sub.Err().Error() } var ( - err = fmt.Errorf("subscription was cancelled (reason: %s)", reason) + err = fmt.Errorf("subscription was canceled (reason: %s)", reason) resp = rpctypes.RPCServerError(subscriptionID, err) ) if !ctx.WSConn.TryWriteRPCResponse(resp) { diff --git a/rpc/core/mempool.go b/rpc/core/mempool.go index f9fa4b37e..8e8dbdcf2 100644 --- a/rpc/core/mempool.go +++ b/rpc/core/mempool.go @@ -128,7 +128,7 @@ func BroadcastTxCommit(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadc } else { reason = deliverTxSub.Err().Error() } - err = fmt.Errorf("deliverTxSub was cancelled (reason: %s)", reason) + err = fmt.Errorf("deliverTxSub was canceled (reason: %s)", reason) env.Logger.Error("Error on broadcastTxCommit", "err", err) return &ctypes.ResultBroadcastTxCommit{ CheckTx: *checkTxRes, diff --git a/rpc/core/tx.go b/rpc/core/tx.go index 1dc9df7c0..e7537e353 100644 --- a/rpc/core/tx.go +++ b/rpc/core/tx.go @@ -32,19 +32,16 @@ func Tx(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error return nil, fmt.Errorf("tx (%X) not found", hash) } - height := r.Height - index := r.Index - var proof types.TxProof if prove { - block := env.BlockStore.LoadBlock(height) - proof = block.Data.Txs.Proof(int(index)) // XXX: overflow on 32-bit machines + block := env.BlockStore.LoadBlock(r.Height) + proof = block.Data.Txs.Proof(int(r.Index)) } return &ctypes.ResultTx{ Hash: hash, - Height: height, - Index: index, + Height: r.Height, + Index: r.Index, TxResult: r.Result, Tx: r.Tx, Proof: proof, @@ -118,7 +115,7 @@ func TxSearch( var proof types.TxProof if prove { block := env.BlockStore.LoadBlock(r.Height) - proof = block.Data.Txs.Proof(int(r.Index)) // XXX: overflow on 32-bit machines + proof = block.Data.Txs.Proof(int(r.Index)) } apiResults = append(apiResults, &ctypes.ResultTx{ diff --git a/rpc/jsonrpc/server/ws_handler.go b/rpc/jsonrpc/server/ws_handler.go index e4e5d7504..f8a89714e 100644 --- a/rpc/jsonrpc/server/ws_handler.go +++ b/rpc/jsonrpc/server/ws_handler.go @@ -49,7 +49,7 @@ func NewWebsocketManager( CheckOrigin: func(r *http.Request) bool { // TODO ??? // - // The default behaviour would be relevant to browser-based clients, + // The default behavior would be relevant to browser-based clients, // afaik. I suppose having a pass-through is a workaround for allowing // for more complex security schemes, shifting the burden of // AuthN/AuthZ outside the Tendermint RPC. diff --git a/rpc/openapi/openapi.yaml b/rpc/openapi/openapi.yaml index 190def7e7..ef06f9e63 100644 --- a/rpc/openapi/openapi.yaml +++ b/rpc/openapi/openapi.yaml @@ -537,8 +537,7 @@ paths: type: array items: type: string - example: - ["f9baeaa15fedf5e1ef7448dd60f46c01f1a9e9c4@1.2.3.4:26656"] + example: "f9baeaa15fedf5e1ef7448dd60f46c01f1a9e9c4@1.2.3.4:26656" responses: "200": description: Dialing seeds in progress. See /net_info for details @@ -588,8 +587,7 @@ paths: type: array items: type: string - example: - ["f9baeaa15fedf5e1ef7448dd60f46c01f1a9e9c4@1.2.3.4:26656"] + example: "f9baeaa15fedf5e1ef7448dd60f46c01f1a9e9c4@1.2.3.4:26656" responses: "200": description: Dialing seeds in progress. See /net_info for details @@ -1674,7 +1672,7 @@ components: nullable: false items: $ref: "#/components/schemas/Event" - end_block: + end_block_events: type: array nullable: true items: @@ -1709,7 +1707,7 @@ components: power: type: string example: "300" - consensus_params_updates: + consensus_param_updates: $ref: "#/components/schemas/ConsensusParams" CommitResponse: @@ -2742,6 +2740,33 @@ components: type: string example: "Dialing seeds in progress. See /net_info for details" + BlockSearchResponse: + type: object + required: + - "jsonrpc" + - "id" + - "result" + properties: + jsonrpc: + type: string + example: "2.0" + id: + type: integer + example: 0 + result: + required: + - "blocks" + - "total_count" + properties: + blocks: + type: array + items: + $ref: "#/components/schemas/BlockComplete" + total_count: + type: integer + example: 2 + type: object + ###### Reuseable types ###### # Validator type with proposer prioirty diff --git a/state/execution.go b/state/execution.go index f05edf953..af05160af 100644 --- a/state/execution.go +++ b/state/execution.go @@ -9,7 +9,7 @@ import ( cryptoenc "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/libs/fail" "github.com/tendermint/tendermint/libs/log" - mempl "github.com/tendermint/tendermint/mempool" + "github.com/tendermint/tendermint/mempool" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/proxy" @@ -34,7 +34,7 @@ type BlockExecutor struct { // manage the mempool lock during commit // and update both with block results after commit. - mempool mempl.Mempool + mempool mempool.Mempool evpool EvidencePool logger log.Logger @@ -56,7 +56,7 @@ func NewBlockExecutor( stateStore Store, logger log.Logger, proxyApp proxy.AppConnConsensus, - mempool mempl.Mempool, + mempool mempool.Mempool, evpool EvidencePool, options ...BlockExecutorOption, ) *BlockExecutor { @@ -95,9 +95,11 @@ func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) // Contract: application will not return more bytes than are sent over the wire. func (blockExec *BlockExecutor) CreateProposalBlock( height int64, - state State, commit *types.Commit, + state State, + commit *types.Commit, proposerAddr []byte, -) (*types.Block, *types.PartSet) { + votes []*types.Vote, +) (*types.Block, error) { maxBytes := state.ConsensusParams.Block.MaxBytes maxGas := state.ConsensusParams.Block.MaxGas @@ -108,9 +110,18 @@ func (blockExec *BlockExecutor) CreateProposalBlock( maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size()) txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas) + block := state.MakeBlock(height, txs, commit, evidence, proposerAddr) - preparedProposal, err := blockExec.proxyApp.PrepareProposalSync( - abci.RequestPrepareProposal{BlockData: txs.ToSliceOfBytes(), BlockDataSize: maxDataBytes}, + localLastCommit := getBeginBlockValidatorInfo(block, blockExec.store, state.InitialHeight) + rpp, err := blockExec.proxyApp.PrepareProposalSync( + abci.RequestPrepareProposal{ + Hash: block.Hash(), + Header: *block.Header.ToProto(), + Txs: block.Txs.ToSliceOfBytes(), + LocalLastCommit: extendedCommitInfo(localLastCommit, votes), + ByzantineValidators: block.Evidence.Evidence.ToABCI(), + MaxTxBytes: maxDataBytes, + }, ) if err != nil { // The App MUST ensure that only valid (and hence 'processable') transactions @@ -118,24 +129,24 @@ func (blockExec *BlockExecutor) CreateProposalBlock( // transaction causing an error. // // Also, the App can simply skip any transaction that could cause any kind of trouble. - // Either way, we can not recover in a meaningful way, unless we skip proposing - // this block, repair what caused the error and try again. Hence, we panic on - // purpose for now. - panic(err) + // Either way, we cannot recover in a meaningful way, unless we skip proposing + // this block, repair what caused the error and try again. Hence, we return an + // error for now (the production code calling this function is expected to panic). + return nil, err } - newTxs := preparedProposal.GetBlockData() - var txSize int - for _, tx := range newTxs { - txSize += len(tx) + txrSet := types.NewTxRecordSet(rpp.TxRecords) - if maxDataBytes < int64(txSize) { - panic("block data exceeds max amount of allowed bytes") + if err := txrSet.Validate(maxDataBytes, block.Txs); err != nil { + return nil, err + } + + for _, rtx := range txrSet.RemovedTxs() { + if err := blockExec.mempool.RemoveTxByKey(rtx.Key()); err != nil { + blockExec.logger.Debug("error removing transaction from the mempool", "error", err, "tx hash", rtx.Hash()) } } - - modifiedTxs := types.ToTxs(preparedProposal.GetBlockData()) - - return state.MakeBlock(height, modifiedTxs, commit, evidence, proposerAddr) + itxs := txrSet.IncludedTxs() + return state.MakeBlock(height, itxs, commit, evidence, proposerAddr), nil } func (blockExec *BlockExecutor) ProcessProposal( @@ -424,6 +435,24 @@ func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) a } } +func extendedCommitInfo(c abci.LastCommitInfo, votes []*types.Vote) abci.ExtendedCommitInfo { + vs := make([]abci.ExtendedVoteInfo, len(c.Votes)) + for i := range vs { + vs[i] = abci.ExtendedVoteInfo{ + Validator: c.Votes[i].Validator, + SignedLastBlock: c.Votes[i].SignedLastBlock, + /* + TODO: Include vote extensions information when implementing vote extensions. + VoteExtension: []byte{}, + */ + } + } + return abci.ExtendedCommitInfo{ + Round: c.Round, + Votes: vs, + } +} + func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate, params tmproto.ValidatorParams) error { for _, valUpdate := range abciUpdates { diff --git a/state/execution_test.go b/state/execution_test.go index df260f387..6a8809cc8 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -2,6 +2,7 @@ package state_test import ( "context" + "errors" "testing" "time" @@ -9,25 +10,26 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + abciclientmocks "github.com/tendermint/tendermint/abci/client/mocks" abci "github.com/tendermint/tendermint/abci/types" + abcimocks "github.com/tendermint/tendermint/abci/types/mocks" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" cryptoenc "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/libs/log" - mmock "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmversion "github.com/tendermint/tendermint/proto/tendermint/version" "github.com/tendermint/tendermint/proxy" + pmocks "github.com/tendermint/tendermint/proxy/mocks" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/state/mocks" sf "github.com/tendermint/tendermint/state/test/factory" - "github.com/tendermint/tendermint/store" "github.com/tendermint/tendermint/test/factory" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" "github.com/tendermint/tendermint/version" - dbm "github.com/tendermint/tm-db" ) var ( @@ -45,12 +47,24 @@ func TestApplyBlock(t *testing.T) { state, stateDB, _ := makeState(1, 1) stateStore := sm.NewStore(stateDB) - + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mmock.Mempool{}, sm.EmptyEvidencePool{}) + mp, sm.EmptyEvidencePool{}) block := sf.MakeBlock(state, 1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} state, retainHeight, err := blockExec.ApplyBlock(state, blockID, block) require.Nil(t, err) @@ -200,14 +214,28 @@ func TestBeginBlockByzantineValidators(t *testing.T) { evpool.On("PendingEvidence", mock.AnythingOfType("int64")).Return(ev, int64(100)) evpool.On("Update", mock.AnythingOfType("state.State"), mock.AnythingOfType("types.EvidenceList")).Return() evpool.On("CheckEvidence", mock.AnythingOfType("types.EvidenceList")).Return(nil) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mmock.Mempool{}, evpool) + mp, evpool) block := sf.MakeBlock(state, 1, new(types.Commit)) block.Evidence = types.EvidenceData{Evidence: ev} block.Header.EvidenceHash = block.Evidence.Hash() - blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} state, retainHeight, err := blockExec.ApplyBlock(state, blockID, block) require.Nil(t, err) @@ -220,44 +248,42 @@ func TestBeginBlockByzantineValidators(t *testing.T) { func TestProcessProposal(t *testing.T) { const height = 2 txs := factory.MakeNTxs(height, 10) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - app := abcimocks.NewApplication(t) logger := log.NewNopLogger() - cc := abciclient.NewLocalClient(logger, app) - proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) - err := proxyApp.Start(ctx) + app := abcimocks.NewBaseMock() + app.On("ProcessProposal", mock.Anything).Return(abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}) + + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests state, stateDB, privVals := makeState(1, height) stateStore := sm.NewStore(stateDB) - blockStore := store.NewBlockStore(dbm.NewMemDB()) - eventBus := eventbus.NewDefault(logger) - require.NoError(t, eventBus.Start(ctx)) + eventBus := types.NewEventBus() + err = eventBus.Start() + require.NoError(t, err) blockExec := sm.NewBlockExecutor( stateStore, logger, - proxyApp, + proxyApp.Consensus(), new(mpmocks.Mempool), sm.EmptyEvidencePool{}, - blockStore, - eventBus, - sm.NopMetrics(), ) block0 := sf.MakeBlock(state, height-1, new(types.Commit)) lastCommitSig := []types.CommitSig{} - partSet := block0.MakePartSet(types.BlockPartSizeBytes) + partSet, err := block0.MakePartSet(types.BlockPartSizeBytes) require.NoError(t, err) blockID := types.BlockID{Hash: block0.Hash(), PartSetHeader: partSet.Header()} voteInfos := []abci.VoteInfo{} for _, privVal := range privVals { - vote, err := factory.MakeVote(ctx, privVal, block0.Header.ChainID, 0, 0, 0, 2, blockID, time.Now()) + vote, err := types.MakeVote(height, blockID, state.Validators, privVal, block0.Header.ChainID, time.Now()) require.NoError(t, err) - pk, err := privVal.GetPubKey(ctx) + pk, err := privVal.GetPubKey() require.NoError(t, err) addr := pk.Address() voteInfos = append(voteInfos, @@ -277,12 +303,12 @@ func TestProcessProposal(t *testing.T) { }) block1.Txs = txs - expectedRpp := &abci.RequestProcessProposal{ + expectedRpp := abci.RequestProcessProposal{ Txs: block1.Txs.ToSliceOfBytes(), Hash: block1.Hash(), Height: block1.Header.Height, Time: block1.Header.Time, - Misbehavior: block1.Evidence.ToABCI(), + Misbehavior: block1.Evidence.Evidence.ToABCI(), ProposedLastCommit: abci.CommitInfo{ Round: 0, Votes: voteInfos, @@ -291,12 +317,11 @@ func TestProcessProposal(t *testing.T) { ProposerAddress: block1.ProposerAddress, } - app.On("ProcessProposal", mock.Anything, mock.Anything).Return(&abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil) - acceptBlock, err := blockExec.ProcessProposal(ctx, block1, state) + acceptBlock, err := blockExec.ProcessProposal(block1, state) require.NoError(t, err) require.True(t, acceptBlock) app.AssertExpectations(t) - app.AssertCalled(t, "ProcessProposal", ctx, expectedRpp) + app.AssertCalled(t, "ProcessProposal", expectedRpp) } func TestValidateValidatorUpdates(t *testing.T) { @@ -440,12 +465,24 @@ func TestEndBlockValidatorUpdates(t *testing.T) { state, stateDB, _ := makeState(1, 1) stateStore := sm.NewStore(stateDB) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs{}) blockExec := sm.NewBlockExecutor( stateStore, log.TestingLogger(), proxyApp.Consensus(), - mmock.Mempool{}, + mp, sm.EmptyEvidencePool{}, ) @@ -464,7 +501,9 @@ func TestEndBlockValidatorUpdates(t *testing.T) { require.NoError(t, err) block := sf.MakeBlock(state, 1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} pubkey := ed25519.GenPrivKey().PubKey() pk, err := cryptoenc.PubKeyToProto(pubkey) @@ -493,7 +532,7 @@ func TestEndBlockValidatorUpdates(t *testing.T) { assert.EqualValues(t, 10, event.ValidatorUpdates[0].VotingPower) } case <-updatesSub.Cancelled(): - t.Fatalf("updatesSub was cancelled (reason: %v)", updatesSub.Err()) + t.Fatalf("updatesSub was canceled (reason: %v)", updatesSub.Err()) case <-time.After(1 * time.Second): t.Fatal("Did not receive EventValidatorSetUpdates within 1 sec.") } @@ -515,12 +554,14 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { stateStore, log.TestingLogger(), proxyApp.Consensus(), - mmock.Mempool{}, + new(mpmocks.Mempool), sm.EmptyEvidencePool{}, ) block := sf.MakeBlock(state, 1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} vp, err := cryptoenc.PubKeyToProto(state.Validators.Validators[0].PubKey) require.NoError(t, err) @@ -534,6 +575,344 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { assert.NotEmpty(t, state.NextValidators.Validators) } +func TestEmptyPrepareProposal(t *testing.T) { + const height = 2 + + app := abcimocks.NewBaseMock() + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs{}) + + blockExec := sm.NewBlockExecutor( + stateStore, + log.TestingLogger(), + proxyApp.Consensus(), + mp, + sm.EmptyEvidencePool{}, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + _, err = blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.NoError(t, err) +} + +// TestPrepareProposalErrorOnNonExistingRemoved tests that the block creation logic returns +// an error if the ResponsePrepareProposal returned from the application marks +// a transaction as REMOVED that was not present in the original proposal. +func TestPrepareProposalErrorOnNonExistingRemoved(t *testing.T) { + const height = 2 + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs{}) + + // create an invalid ResponsePrepareProposal + rpp := abci.ResponsePrepareProposal{ + TxRecords: []*abci.TxRecord{ + { + Action: abci.TxRecord_REMOVED, + Tx: []byte("new tx"), + }, + }, + } + + app := abcimocks.NewBaseMock() + app.On("PrepareProposal", mock.Anything).Return(rpp) + + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + blockExec := sm.NewBlockExecutor( + stateStore, + log.TestingLogger(), + proxyApp.Consensus(), + mp, + evpool, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.Nil(t, block) + require.ErrorContains(t, err, "new transaction incorrectly marked as removed") + + mp.AssertExpectations(t) +} + +// TestPrepareProposalRemoveTxs tests that any transactions marked as REMOVED +// are not included in the block produced by CreateProposalBlock. The test also +// ensures that any transactions removed are also removed from the mempool. +func TestPrepareProposalRemoveTxs(t *testing.T) { + const height = 2 + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + txs := factory.MakeNTxs(height, 10) + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) + + trs := txsToTxRecords(types.Txs(txs)) + trs[0].Action = abci.TxRecord_REMOVED + trs[1].Action = abci.TxRecord_REMOVED + mp.On("RemoveTxByKey", mock.Anything).Return(nil).Twice() + + app := abcimocks.NewBaseMock() + app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ + TxRecords: trs, + }) + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + blockExec := sm.NewBlockExecutor( + stateStore, + log.TestingLogger(), + proxyApp.Consensus(), + mp, + evpool, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.NoError(t, err) + require.Len(t, block.Data.Txs.ToSliceOfBytes(), len(trs)-2) + + require.Equal(t, -1, block.Data.Txs.Index(types.Tx(trs[0].Tx))) + require.Equal(t, -1, block.Data.Txs.Index(types.Tx(trs[1].Tx))) + + mp.AssertCalled(t, "RemoveTxByKey", types.Tx(trs[0].Tx).Key()) + mp.AssertCalled(t, "RemoveTxByKey", types.Tx(trs[1].Tx).Key()) + mp.AssertExpectations(t) +} + +// TestPrepareProposalAddedTxsIncluded tests that any transactions marked as ADDED +// in the prepare proposal response are included in the block. +func TestPrepareProposalAddedTxsIncluded(t *testing.T) { + const height = 2 + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + txs := factory.MakeNTxs(height, 10) + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs[2:])) + + trs := txsToTxRecords(types.Txs(txs)) + trs[0].Action = abci.TxRecord_ADDED + trs[1].Action = abci.TxRecord_ADDED + + app := abcimocks.NewBaseMock() + app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ + TxRecords: trs, + }) + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + blockExec := sm.NewBlockExecutor( + stateStore, + log.TestingLogger(), + proxyApp.Consensus(), + mp, + evpool, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.NoError(t, err) + + require.Equal(t, txs[0], block.Data.Txs[0]) + require.Equal(t, txs[1], block.Data.Txs[1]) + + mp.AssertExpectations(t) +} + +// TestPrepareProposalReorderTxs tests that CreateBlock produces a block with transactions +// in the order matching the order they are returned from PrepareProposal. +func TestPrepareProposalReorderTxs(t *testing.T) { + const height = 2 + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + txs := factory.MakeNTxs(height, 10) + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) + + trs := txsToTxRecords(types.Txs(txs)) + trs = trs[2:] + trs = append(trs[len(trs)/2:], trs[:len(trs)/2]...) + + app := abcimocks.NewBaseMock() + app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ + TxRecords: trs, + }) + + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + blockExec := sm.NewBlockExecutor( + stateStore, + log.TestingLogger(), + proxyApp.Consensus(), + mp, + evpool, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.NoError(t, err) + for i, tx := range block.Data.Txs { + require.Equal(t, types.Tx(trs[i].Tx), tx) + } + + mp.AssertExpectations(t) + +} + +// TestPrepareProposalErrorOnTooManyTxs tests that the block creation logic returns +// an error if the ResponsePrepareProposal returned from the application is invalid. +func TestPrepareProposalErrorOnTooManyTxs(t *testing.T) { + const height = 2 + + state, stateDB, privVals := makeState(1, height) + // limit max block size + state.ConsensusParams.Block.MaxBytes = 60 * 1024 + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + const nValidators = 1 + var bytesPerTx int64 = 3 + maxDataBytes := types.MaxDataBytes(state.ConsensusParams.Block.MaxBytes, 0, nValidators) + txs := factory.MakeNTxs(height, maxDataBytes/bytesPerTx+2) // +2 so that tx don't fit + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) + + trs := txsToTxRecords(types.Txs(txs)) + + app := abcimocks.NewBaseMock() + app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ + TxRecords: trs, + }) + + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + blockExec := sm.NewBlockExecutor( + stateStore, + log.NewNopLogger(), + proxyApp.Consensus(), + mp, + evpool, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + + block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.Nil(t, block) + require.ErrorContains(t, err, "transaction data size exceeds maximum") + + mp.AssertExpectations(t) +} + +// TestPrepareProposalErrorOnPrepareProposalError tests when the client returns an error +// upon calling PrepareProposal on it. +func TestPrepareProposalErrorOnPrepareProposalError(t *testing.T) { + const height = 2 + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + txs := factory.MakeNTxs(height, 10) + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) + + cm := &abciclientmocks.Client{} + cm.On("SetLogger", mock.Anything).Return() + cm.On("Start").Return(nil) + cm.On("Quit").Return(nil) + cm.On("PrepareProposalSync", mock.Anything).Return(nil, errors.New("an injected error")).Once() + cm.On("Stop").Return(nil) + cc := &pmocks.ClientCreator{} + cc.On("NewABCIClient").Return(cm, nil) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + blockExec := sm.NewBlockExecutor( + stateStore, + log.NewNopLogger(), + proxyApp.Consensus(), + mp, + evpool, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + + block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.Nil(t, block) + require.ErrorContains(t, err, "an injected error") + + mp.AssertExpectations(t) +} + func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.BlockID { var ( h = make([]byte, tmhash.Size) @@ -549,3 +928,14 @@ func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.Bloc }, } } + +func txsToTxRecords(txs []types.Tx) []*abci.TxRecord { + trs := make([]*abci.TxRecord, len(txs)) + for i, tx := range txs { + trs[i] = &abci.TxRecord{ + Action: abci.TxRecord_UNMODIFIED, + Tx: tx, + } + } + return trs +} diff --git a/state/helpers_test.go b/state/helpers_test.go index 806f1abd7..35d0c403c 100644 --- a/state/helpers_test.go +++ b/state/helpers_test.go @@ -3,6 +3,7 @@ package state_test import ( "bytes" "fmt" + "testing" "time" dbm "github.com/tendermint/tm-db" @@ -10,7 +11,6 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" - tmrand "github.com/tendermint/tendermint/libs/rand" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/proxy" @@ -56,13 +56,18 @@ func makeAndCommitGoodBlock( func makeAndApplyGoodBlock(state sm.State, height int64, lastCommit *types.Commit, proposerAddr []byte, blockExec *sm.BlockExecutor, evidence []types.Evidence) (sm.State, types.BlockID, error) { - block, _ := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + block := state.MakeBlock(height, factory.MakeNTxs(height, 10), lastCommit, evidence, proposerAddr) + partSet, err := block.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + return state, types.BlockID{}, err + } + if err := blockExec.ValidateBlock(state, block); err != nil { return state, types.BlockID{}, err } blockID := types.BlockID{Hash: block.Hash(), - PartSetHeader: types.PartSetHeader{Total: 3, Hash: tmrand.Bytes(32)}} - state, _, err := blockExec.ApplyBlock(state, blockID, block) + PartSetHeader: partSet.Header()} + state, _, err = blockExec.ApplyBlock(state, blockID, block) if err != nil { return state, types.BlockID{}, err } @@ -134,6 +139,7 @@ func genValSet(size int) *types.ValidatorSet { } func makeHeaderPartsResponsesValPubKeyChange( + t *testing.T, state sm.State, pubkey crypto.PubKey, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { @@ -158,6 +164,7 @@ func makeHeaderPartsResponsesValPubKeyChange( } func makeHeaderPartsResponsesValPowerChange( + t *testing.T, state sm.State, power int64, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { @@ -182,6 +189,7 @@ func makeHeaderPartsResponsesValPowerChange( } func makeHeaderPartsResponsesParams( + t *testing.T, state sm.State, params tmproto.ConsensusParams, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { diff --git a/state/state.go b/state/state.go index a1df48d45..8082da7b8 100644 --- a/state/state.go +++ b/state/state.go @@ -238,7 +238,7 @@ func (state State) MakeBlock( commit *types.Commit, evidence []types.Evidence, proposerAddress []byte, -) (*types.Block, *types.PartSet) { +) *types.Block { // Build base block with block data. block := types.MakeBlock(height, txs, commit, evidence) @@ -260,7 +260,7 @@ func (state State) MakeBlock( proposerAddress, ) - return block, block.MakePartSet(types.BlockPartSizeBytes) + return block } // MedianTime computes a median time for a given Commit (based on Timestamp field of votes messages) and the diff --git a/state/state_test.go b/state/state_test.go index 5f41ffe8f..e943c37a0 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -42,7 +42,7 @@ func setupTestCase(t *testing.T) (func(t *testing.T), dbm.DB, sm.State) { return tearDown, stateDB, state } -// TestStateCopy tests the correct copying behaviour of State. +// TestStateCopy tests the correct copying behavior of State. func TestStateCopy(t *testing.T) { tearDown, _, state := setupTestCase(t) defer tearDown(t) @@ -270,12 +270,12 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) { changeIndex++ power++ } - header, blockID, responses := makeHeaderPartsResponsesValPowerChange(state, power) + header, blockID, responses := makeHeaderPartsResponsesValPowerChange(t, state, power) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) require.NoError(t, err) state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) require.NoError(t, err) - err := stateStore.Save(state) + err = stateStore.Save(state) require.NoError(t, err) } @@ -445,7 +445,9 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { assert.EqualValues(t, 0, val1.ProposerPriority) block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, @@ -559,7 +561,9 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { assert.Equal(t, val1PubKey.Address(), state.Validators.Proposer.Address) block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} // no updates: abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, @@ -746,7 +750,9 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) @@ -775,7 +781,11 @@ func TestLargeGenesisValidator(t *testing.T) { EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}}, } block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) @@ -790,7 +800,11 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) block := sf.MakeBlock(lastState, lastState.LastBlockHeight+1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + + bps, err = block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} updatedStateInner, err := sm.UpdateState(lastState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) @@ -823,7 +837,10 @@ func TestLargeGenesisValidator(t *testing.T) { EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}}, } block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} state, err = sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) } @@ -837,8 +854,14 @@ func TestLargeGenesisValidator(t *testing.T) { BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}}, } + block = sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) - blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + require.NoError(t, err) + + bps, err = block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) updatedState, err = sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) @@ -859,7 +882,11 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) block = sf.MakeBlock(curState, curState.LastBlockHeight+1, new(types.Commit)) - blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} curState, err = sm.UpdateState(curState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) if !bytes.Equal(curState.Validators.Proposer.Address, curState.NextValidators.Proposer.Address) { @@ -884,7 +911,11 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) block := sf.MakeBlock(updatedState, updatedState.LastBlockHeight+1, new(types.Commit)) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} updatedState, err = sm.UpdateState(updatedState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) @@ -939,7 +970,7 @@ func TestManyValidatorChangesSaveLoad(t *testing.T) { pubkey := ed25519.GenPrivKey().PubKey() // Swap the first validator with a new one (validator set size stays the same). - header, blockID, responses := makeHeaderPartsResponsesValPubKeyChange(state, pubkey) + header, blockID, responses := makeHeaderPartsResponsesValPubKeyChange(t, state, pubkey) // Save state etc. var validatorUpdates []*types.Validator @@ -1020,13 +1051,13 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) { changeIndex++ cp = params[changeIndex] } - header, blockID, responses := makeHeaderPartsResponsesParams(state, cp) + header, blockID, responses := makeHeaderPartsResponsesParams(t, state, cp) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) require.NoError(t, err) state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) - require.Nil(t, err) - err := stateStore.Save(state) + require.NoError(t, err) + err = stateStore.Save(state) require.NoError(t, err) } diff --git a/state/test/factory/block.go b/state/test/factory/block.go index a8187ac33..42d88d428 100644 --- a/state/test/factory/block.go +++ b/state/test/factory/block.go @@ -8,8 +8,8 @@ import ( "github.com/tendermint/tendermint/types" ) -func MakeBlocks(n int, state *sm.State, privVal types.PrivValidator) []*types.Block { - blocks := make([]*types.Block, 0) +func MakeBlocks(n int, state *sm.State, privVal types.PrivValidator) ([]*types.Block, error) { + blocks := make([]*types.Block, n) var ( prevBlock *types.Block @@ -20,8 +20,12 @@ func MakeBlocks(n int, state *sm.State, privVal types.PrivValidator) []*types.Bl for i := 0; i < n; i++ { height := int64(i + 1) - block, parts := makeBlockAndPartSet(*state, prevBlock, prevBlockMeta, privVal, height) - blocks = append(blocks, block) + block, parts, err := makeBlockAndPartSet(*state, prevBlock, prevBlockMeta, privVal, height) + if err != nil { + return nil, err + } + + blocks[i] = block prevBlock = block prevBlockMeta = types.NewBlockMeta(block, parts) @@ -32,23 +36,26 @@ func MakeBlocks(n int, state *sm.State, privVal types.PrivValidator) []*types.Bl state.LastBlockHeight = height } - return blocks + return blocks, nil } func MakeBlock(state sm.State, height int64, c *types.Commit) *types.Block { - block, _ := state.MakeBlock( + return state.MakeBlock( height, - factory.MakeTenTxs(state.LastBlockHeight), + factory.MakeNTxs(state.LastBlockHeight, 10), c, nil, state.Validators.GetProposer().Address, ) - return block } -func makeBlockAndPartSet(state sm.State, lastBlock *types.Block, lastBlockMeta *types.BlockMeta, - privVal types.PrivValidator, height int64) (*types.Block, *types.PartSet) { - +func makeBlockAndPartSet( + state sm.State, + lastBlock *types.Block, + lastBlockMeta *types.BlockMeta, + privVal types.PrivValidator, + height int64, +) (*types.Block, *types.PartSet, error) { lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil) if height > 1 { vote, _ := types.MakeVote( @@ -62,5 +69,7 @@ func makeBlockAndPartSet(state sm.State, lastBlock *types.Block, lastBlockMeta * lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) } - return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) + block := state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) + partSet, err := block.MakePartSet(types.BlockPartSizeBytes) + return block, partSet, err } diff --git a/state/txindex/mocks/tx_indexer.go b/state/txindex/mocks/tx_indexer.go index 5a109672e..64dd50ec7 100644 --- a/state/txindex/mocks/tx_indexer.go +++ b/state/txindex/mocks/tx_indexer.go @@ -6,7 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - query "github.com/tendermint/tendermint/libs/pubsub/query" txindex "github.com/tendermint/tendermint/state/txindex" diff --git a/state/validation_test.go b/state/validation_test.go index 0c430df15..9fa2f16f4 100644 --- a/state/validation_test.go +++ b/state/validation_test.go @@ -12,7 +12,7 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/libs/log" - memmock "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/state/mocks" @@ -22,7 +22,11 @@ import ( tmtime "github.com/tendermint/tendermint/types/time" ) -const validationTestsStopHeight int64 = 10 +const ( + validationTestsStopHeight int64 = 10 + chainID = "execution_chain" +) + func TestValidateBlockHeader(t *testing.T) { proxyApp := newTestApp() @@ -31,11 +35,23 @@ func TestValidateBlockHeader(t *testing.T) { state, stateDB, privVals := makeState(3, 1) stateStore := sm.NewStore(stateDB) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + blockExec := sm.NewBlockExecutor( stateStore, log.TestingLogger(), proxyApp.Consensus(), - memmock.Mempool{}, + mp, sm.EmptyEvidencePool{}, ) lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) @@ -102,11 +118,23 @@ func TestValidateBlockCommit(t *testing.T) { state, stateDB, privVals := makeState(1, 1) stateStore := sm.NewStore(stateDB) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + blockExec := sm.NewBlockExecutor( stateStore, log.TestingLogger(), proxyApp.Consensus(), - memmock.Mempool{}, + mp, sm.EmptyEvidencePool{}, ) lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) @@ -224,12 +252,23 @@ func TestValidateBlockEvidence(t *testing.T) { evpool.On("ABCIEvidence", mock.AnythingOfType("int64"), mock.AnythingOfType("[]types.Evidence")).Return( []abci.Evidence{}) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) state.ConsensusParams.Evidence.MaxBytes = 1000 blockExec := sm.NewBlockExecutor( stateStore, log.TestingLogger(), proxyApp.Consensus(), - memmock.Mempool{}, + mp, evpool, ) lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) @@ -250,7 +289,8 @@ func TestValidateBlockEvidence(t *testing.T) { evidence = append(evidence, newEv) currentBytes += int64(len(newEv.Bytes())) } - block, _ := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + block := state.MakeBlock(height, factory.MakeNTxs(height, 10), lastCommit, evidence, proposerAddr) + err := blockExec.ValidateBlock(state, block) if assert.Error(t, err) { _, ok := err.(*types.ErrEvidenceOverflow) diff --git a/statesync/syncer.go b/statesync/syncer.go index e4c02988b..e1c46a634 100644 --- a/statesync/syncer.go +++ b/statesync/syncer.go @@ -267,7 +267,7 @@ func (s *syncer) Sync(snapshot *snapshot, chunks *chunkQueue) (sm.State, *types. return sm.State{}, nil, err } - // Spawn chunk fetchers. They will terminate when the chunk queue is closed or context cancelled. + // Spawn chunk fetchers. They will terminate when the chunk queue is closed or context canceled. fetchCtx, cancel := context.WithCancel(context.TODO()) defer cancel() for i := int32(0); i < s.chunkFetchers; i++ { diff --git a/store/store_test.go b/store/store_test.go index b28342583..db6cea4c2 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -3,6 +3,7 @@ package store import ( "bytes" "fmt" + stdlog "log" "os" "runtime/debug" "strings" @@ -133,9 +134,14 @@ var ( func TestMain(m *testing.M) { var cleanup cleanupFunc + var err error state, _, cleanup = makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer))) block = factory.MakeBlock(state, 1, new(types.Commit)) - partSet = block.MakePartSet(2) + + partSet, err = block.MakePartSet(2) + if err != nil { + stdlog.Fatal(err) + } part1 = partSet.GetPart(0) part2 = partSet.GetPart(1) seenCommit1 = makeTestCommit(10, tmtime.Now()) @@ -162,7 +168,8 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) { // save a block block := factory.MakeBlock(state, bs.Height()+1, new(types.Commit)) - validPartSet := block.MakePartSet(2) + validPartSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(10, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) require.EqualValues(t, 1, bs.Base(), "expecting the new height to be changed") @@ -170,7 +177,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) { incompletePartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 2}) uncontiguousPartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 0}) - _, err := uncontiguousPartSet.AddPart(part2) + _, err = uncontiguousPartSet.AddPart(part2) require.Error(t, err) header1 := types.Header{ @@ -365,7 +372,8 @@ func TestLoadBaseMeta(t *testing.T) { for h := int64(1); h <= 10; h++ { block := factory.MakeBlock(state, h, new(types.Commit)) - partSet := block.MakePartSet(2) + partSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(h, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) } @@ -433,7 +441,8 @@ func TestPruneBlocks(t *testing.T) { // make more than 1000 blocks, to test batch deletions for h := int64(1); h <= 1500; h++ { block := factory.MakeBlock(state, h, new(types.Commit)) - partSet := block.MakePartSet(2) + partSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(h, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) } @@ -543,7 +552,8 @@ func TestBlockFetchAtHeight(t *testing.T) { require.Equal(t, bs.Height(), int64(0), "initially the height should be zero") block := factory.MakeBlock(state, bs.Height()+1, new(types.Commit)) - partSet := block.MakePartSet(2) + partSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(10, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed") diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 6533e6406..ad34fd7e4 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -259,7 +259,20 @@ func (app *Application) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) a func (app *Application) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{BlockData: req.BlockData} + // None of the transactions are modified by this application. + trs := make([]*abci.TxRecord, 0, len(req.Txs)) + var totalBytes int64 + for _, tx := range req.Txs { + totalBytes += int64(len(tx)) + if totalBytes > req.MaxTxBytes { + break + } + trs = append(trs, &abci.TxRecord{ + Action: abci.TxRecord_UNMODIFIED, + Tx: tx, + }) + } + return abci.ResponsePrepareProposal{TxRecords: trs} } // ProcessProposal implements part of the Application interface. diff --git a/test/factory/tx.go b/test/factory/tx.go index c97aeefc9..725f3c720 100644 --- a/test/factory/tx.go +++ b/test/factory/tx.go @@ -2,15 +2,10 @@ package factory import "github.com/tendermint/tendermint/types" -// MakeTxs is a helper function to generate mock transactions by given the block height -// and the transaction numbers. -func MakeTxs(height int64, num int) (txs []types.Tx) { - for i := 0; i < num; i++ { - txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) +func MakeNTxs(height, n int64) []types.Tx { + txs := make([]types.Tx, n) + for i := range txs { + txs[i] = types.Tx([]byte{byte(height), byte(i / 256), byte(i % 256)}) } return txs } - -func MakeTenTxs(height int64) (txs []types.Tx) { - return MakeTxs(height, 10) -} diff --git a/test/maverick/consensus/replay.go b/test/maverick/consensus/replay.go index 227030595..6b8bf06c1 100644 --- a/test/maverick/consensus/replay.go +++ b/test/maverick/consensus/replay.go @@ -56,7 +56,7 @@ func (cs *State) readReplayMessage(msg *tmcon.TimedWALMessage, newStepSub types. return fmt.Errorf("roundState mismatch. Got %v; Expected %v", m2, m) } case <-newStepSub.Cancelled(): - return fmt.Errorf("failed to read off newStepSub.Out(). newStepSub was cancelled") + return fmt.Errorf("failed to read off newStepSub.Out(). newStepSub was canceled") case <-ticker: return fmt.Errorf("failed to read off newStepSub.Out()") } diff --git a/test/maverick/consensus/state.go b/test/maverick/consensus/state.go index e67868214..1cb91682b 100644 --- a/test/maverick/consensus/state.go +++ b/test/maverick/consensus/state.go @@ -396,7 +396,7 @@ func (cs *State) addVote( } // Height mismatch is ignored. - // Not necessarily a bad peer, but not favourable behaviour. + // Not necessarily a bad peer, but not favorable behavior. if vote.Height != cs.Height { cs.Logger.Debug("vote ignored and not added", "voteHeight", vote.Height, "csHeight", cs.Height, "peerID", peerID) return @@ -1202,8 +1202,17 @@ func (cs *State) defaultDecideProposal(height int64, round int32) { block, blockParts = cs.ValidBlock, cs.ValidBlockParts } else { // Create a new proposal block from state/txs from the mempool. - block, blockParts = cs.createProposalBlock() - if block == nil { + var err error + block, err = cs.createProposalBlock() + if err != nil { + cs.Logger.Error("unable to create proposal block", "error", err) + return + } else if block == nil { + return + } + blockParts, err = block.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + cs.Logger.Error("unable to create proposal block part set", "error", err) return } } @@ -1259,9 +1268,9 @@ func (cs *State) isProposalComplete() bool { // // NOTE: keep it side-effect free for clarity. // CONTRACT: cs.privValidator is not nil. -func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.PartSet) { +func (cs *State) createProposalBlock() (*types.Block, error) { if cs.privValidator == nil { - panic("entered createProposalBlock with privValidator being nil") + return nil, errors.New("entered createProposalBlock with privValidator being nil") } var commit *types.Commit @@ -1274,19 +1283,19 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa // Make the commit from LastCommit commit = cs.LastCommit.MakeCommit() default: // This shouldn't happen. - cs.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block") - return + cs.Logger.Error("propose step; cannot propose anything without commit for the previous block") + return nil, nil } if cs.privValidatorPubKey == nil { // If this node is a validator & proposer in the current round, it will // miss the opportunity to create a block. - cs.Logger.Error(fmt.Sprintf("enterPropose: %v", errPubKeyIsNotSet)) - return + cs.Logger.Error("propose step; empty priv validator public key", "err", errPubKeyIsNotSet) + return nil, nil } proposerAddr := cs.privValidatorPubKey.Address() - return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr) + return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) } // Enter: any +2/3 prevotes at next round. diff --git a/tools/mintnet-kubernetes/README.rst b/tools/mintnet-kubernetes/README.rst deleted file mode 100644 index edf5e81e5..000000000 --- a/tools/mintnet-kubernetes/README.rst +++ /dev/null @@ -1,290 +0,0 @@ -Using Kubernetes -================ - -.. figure:: assets/t_plus_k.png - :alt: Tendermint plus Kubernetes - - Tendermint plus Kubernetes - -This should primarily be used for testing purposes or for -tightly-defined chains operated by a single stakeholder (see `the -security precautions <#security>`__). If your desire is to launch an -application with many stakeholders, consider using our set of Ansible -scripts. - -Quick Start ------------ - -For either platform, see the `requirements `__ - -MacOS -^^^^^ - -:: - - curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/kubectl - curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.18.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/ - minikube start - - git clone https://github.com/tendermint/tools.git && cd tools/mintnet-kubernetes/examples/basecoin && make create - -Linux -^^^^^ - -:: - - curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/kubectl - curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.18.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/ - minikube start - - git clone https://github.com/tendermint/tools.git && cd tools/mintnet-kubernetes/examples/basecoin && make create - -Verify it worked -~~~~~~~~~~~~~~~~ - -**Using a shell:** - -First wait until all the pods are ``Running``: - -``kubectl get pods -w -o wide -L tm`` - -then query the Tendermint app logs from the first pod: - -``kubectl logs -c tm -f tm-0`` - -finally, use our `Rest API `__ to fetch the status of the second pod's Tendermint app. - -Note we are using ``kubectl exec`` because pods are not exposed (and should not be) to the -outer network: - -``kubectl exec -c tm tm-0 -- curl -s http://tm-1.basecoin:26657/status | json_pp`` - -**Using the dashboard:** - -:: - - minikube dashboard - -Clean up -~~~~~~~~ - -:: - - make destroy - -Usage ------ - -Setup a Kubernetes cluster -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- locally using `Minikube `__ -- on GCE with a single click in the web UI -- on AWS using `Kubernetes - Operations `__ -- on Linux machines (Digital Ocean) using - `kubeadm `__ -- on AWS, Azure, GCE or bare metal using `Kargo - (Ansible) `__ - -Please refer to `the official -documentation `__ -for overview and comparison of different options. - -Kubernetes on Digital Ocean -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Available options: - -- `kubeadm (alpha) `__ -- `kargo `__ -- `rancher `__ -- `terraform `__ - -As you can see, there is no single tool for creating a cluster on DO. -Therefore, choose the one you know and comfortable working with. If you know -and used `terraform `__ before, then choose it. If you -know Ansible, then pick kargo. If none of these seem familiar to you, go with -``kubeadm``. Rancher is a beautiful UI for deploying and managing containers in -production. - -Kubernetes on Google Cloud Engine -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Review the `Official Documentation `__ for Kubernetes on Google Compute -Engine. - -**Create a cluster** - -The recommended way is to use `Google Container -Engine `__. You should be able -to create a fully fledged cluster with just a few clicks. - -**Connect to it** - -Install ``gcloud`` as a part of `Google Cloud SDK `__. - -Make sure you have credentials for GCloud by running ``gcloud auth login``. - -In order to make API calls against GCE, you must also run ``gcloud auth -application-default login``. - -Press ``Connect``: - -.. figure:: assets/gce1.png - -and execute the first command in your shell. Then start a proxy by -executing ``kubectl` proxy``. - -.. figure:: assets/gce2.png - -Now you should be able to run ``kubectl`` command to create resources, get -resource info, logs, etc. - -**Make sure you have Kubernetes >= 1.5, because you will be using -StatefulSets, which is a beta feature in 1.5.** - -Create a configuration file -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Download a template: - -:: - - curl -Lo app.yaml https://github.com/tendermint/tools/raw/master/mintnet-kubernetes/app.template.yaml - -Open ``app.yaml`` in your favorite editor and configure your app -container (navigate to ``- name: app``). Kubernetes DSL (Domain Specific -Language) is very simple, so it should be easy. You will need to set -Docker image, command and/or run arguments. Replace variables prefixed -with ``YOUR_APP`` with corresponding values. Set genesis time to now and -preferable chain ID in ConfigMap. - -Please note if you are changing ``replicas`` number, do not forget to -update ``validators`` set in ConfigMap. You will be able to scale the -cluster up or down later, but new pods (nodes) won't become validators -automatically. - -Deploy your application -^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - kubectl create -f ./app.yaml - -Observe your cluster -^^^^^^^^^^^^^^^^^^^^ - -`web UI `__ - -The easiest way to access Dashboard is to use ``kubectl``. Run the following -command in your desktop environment: - -:: - - kubectl proxy - -``kubectl`` will handle authentication with apiserver and make Dashboard -available at http://localhost:8001/ui - -**shell** - -List all the pods: - -:: - - kubectl get pods -o wide -L tm - -StatefulSet details: - -:: - - kubectl describe statefulsets tm - -First pod details: - -:: - - kubectl describe pod tm-0 - -Tendermint app logs from the first pod: - -:: - - kubectl logs tm-0 -c tm -f - -App logs from the first pod: - -:: - - kubectl logs tm-0 -c app -f - -Status of the second pod's Tendermint app: - -:: - - kubectl exec -c tm tm-0 -- curl -s http://tm-1.:26657/status | json_pp - -Security --------- - -Due to the nature of Kubernetes, where you typically have a single -master, the master could be a SPOF (Single Point Of Failure). Therefore, -you need to make sure only authorized people can access it. And these -people themselves had taken basic measures in order not to get hacked. - -These are the best practices: - -- all access to the master is over TLS -- access to the API Server is X.509 certificate or token based -- etcd is not exposed directly to the cluster -- ensure that images are free of vulnerabilities - (`1 `__) -- ensure that only authorized images are used in your environment -- disable direct access to Kubernetes nodes (no SSH) -- define resource quota - -Resources: - -- https://kubernetes.io/docs/admin/accessing-the-api/ -- http://blog.kubernetes.io/2016/08/security-best-practices-kubernetes-deployment.html -- https://blog.openshift.com/securing-kubernetes/ - -Fault tolerance ---------------- - -Having a single master (API server) is a bad thing also because if -something happens to it, you risk being left without an access to the -application. - -To avoid that you can `run Kubernetes in multiple -zones `__, each zone -running an `API -server `__ and load -balance requests between them. Do not forget to make sure only one -instance of scheduler and controller-manager are running at once. - -Running in multiple zones is a lightweight version of a broader `Cluster -Federation feature `__. -Federated deployments could span across multiple regions (not zones). We -haven't tried this feature yet, so any feedback is highly appreciated! -Especially, related to additional latency and cost of exchanging data -between the regions. - -Resources: - -- https://kubernetes.io/docs/admin/high-availability/ - -Starting process ----------------- - -.. figure:: assets/statefulset.png - :alt: StatefulSet - - StatefulSet - -Init containers (``tm-gen-validator``) are run before all other -containers, creating public-private key pair for each pod. Every ``tm`` -container then asks other pods for their public keys, which are served -with nginx (``pub-key`` container). When ``tm`` container have all the -keys, it forms a genesis file and starts the Tendermint process. diff --git a/tools/mintnet-kubernetes/app.template.yaml b/tools/mintnet-kubernetes/app.template.yaml deleted file mode 100644 index 826b2e97f..000000000 --- a/tools/mintnet-kubernetes/app.template.yaml +++ /dev/null @@ -1,265 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" - name: YOUR_APP_NAME - labels: - app: YOUR_APP_NAME -spec: - ports: - - port: 26656 - name: p2p - - port: 26657 - name: rpc - clusterIP: None - selector: - app: tm ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: tm-config -data: - seeds: "tm-0,tm-1,tm-2,tm-3" - validators: "tm-0,tm-1,tm-2,tm-3" - validator.power: "10" - genesis.json: |- - { - "genesis_time": "2017-01-02T10:10:10.164Z", - "chain_id": "chain-B5XXm5", - "validators": [], - "app_hash": "" - } - pub_key_nginx.conf: |- - server { - listen 80 default_server; - listen [::]:80 default_server ipv6only=on; - location /pub_key.json { root /usr/share/nginx/; } - } ---- -apiVersion: policy/v1beta1 -kind: PodDisruptionBudget -metadata: - name: tm-budget -spec: - selector: - matchLabels: - app: tm - minAvailable: 2 ---- -apiVersion: apps/v1beta1 -kind: StatefulSet -metadata: - name: tm -spec: - serviceName: YOUR_APP_NAME - replicas: 4 - template: - metadata: - labels: - app: tm - version: v1 - annotations: - pod.beta.kubernetes.io/init-containers: '[{ - "name": "tm-gen-validator", - "image": "tendermint/tendermint:0.10.0", - "imagePullPolicy": "IfNotPresent", - "command": ["bash", "-c", " - set -ex\n - if [ ! -f /tendermint/priv_validator.json ]; then\n - tendermint gen_validator > /tendermint/priv_validator.json\n - # pub_key.json will be served by pub-key container\n - cat /tendermint/priv_validator.json | jq \".pub_key\" > /tendermint/pub_key.json\n - fi\n - "], - "volumeMounts": [ - {"name": "tmdir", "mountPath": "/tendermint"} - ] - }]' - spec: - containers: - - name: tm - imagePullPolicy: IfNotPresent - image: tendermint/tendermint:0.10.0 - resources: - requests: - cpu: 50m - memory: 128Mi - limits: - cpu: 100m - memory: 256Mi - ports: - - containerPort: 26656 - name: p2p - - containerPort: 26657 - name: rpc - env: - - name: SEEDS - valueFrom: - configMapKeyRef: - name: tm-config - key: seeds - - name: VALIDATOR_POWER - valueFrom: - configMapKeyRef: - name: tm-config - key: validator.power - - name: VALIDATORS - valueFrom: - configMapKeyRef: - name: tm-config - key: validators - - name: TMHOME - value: /tendermint - command: - - bash - - "-c" - - | - set -ex - - # copy template - cp /etc/tendermint/genesis.json /tendermint/genesis.json - - # fill genesis file with validators - IFS=',' read -ra VALS_ARR <<< "$VALIDATORS" - fqdn_suffix=$(hostname -f | sed 's#[^.]*\.\(\)#\1#') - for v in "${VALS_ARR[@]}"; do - # wait until validator generates priv/pub key pair - set +e - - curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null - ERR=$? - while [ "$ERR" != 0 ]; do - sleep 5 - curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null - ERR=$? - done - set -e - - # add validator to genesis file along with its pub_key - curl -s "http://$v.$fqdn_suffix/pub_key.json" | jq ". as \$k | {pub_key: \$k, amount: $VALIDATOR_POWER, name: \"$v\"}" > pub_validator.json - cat /tendermint/genesis.json | jq ".validators |= .+ [$(cat pub_validator.json)]" > tmpgenesis && mv tmpgenesis /tendermint/genesis.json - rm pub_validator.json - done - - # construct seeds - IFS=',' read -ra SEEDS_ARR <<< "$SEEDS" - seeds=() - for s in "${SEEDS_ARR[@]}"; do - seeds+=("$s.$fqdn_suffix:26656") - done - seeds=$(IFS=','; echo "${seeds[*]}") - - tendermint node --p2p.seeds="$seeds" --moniker="`hostname`" --proxy_app="unix:///socks/app.sock" - volumeMounts: - - name: tmdir - mountPath: /tendermint - - mountPath: /etc/tendermint/genesis.json - name: configdir - subPath: genesis.json - - name: socksdir - mountPath: /socks - - - name: app - imagePullPolicy: IfNotPresent - image: YOUR_APP_IMAGE - args: ["--addr=\"unix:///socks/app.sock\""] - volumeMounts: - - name: socksdir - mountPath: /socks - - ######## OR ######## - # - # - name: app - # imagePullPolicy: IfNotPresent - # image: golang:1.7.5 - # resources: - # requests: - # cpu: YOUR_APP_CPU_REQ - # memory: YOUR_APP_MEM_REQ - # limits: - # cpu: YOUR_APP_CPU_LIMIT - # memory: YOUR_APP_MEM_LIMIT - # command: - # - bash - # - "-c" - # - | - # set -ex - - # go get -d YOUR_APP_PACKAGE - # cd $GOPATH/YOUR_APP_PACKAGE - # make install - # - # rm -f /socks/app.sock # remove old socket - - # YOUR_APP_EXEC --addr="unix:///socks/app.sock" - # volumeMounts: - # - name: socksdir - # mountPath: /socks - - ######## OPTIONALLY ######## - # - # - name: data - # imagePullPolicy: IfNotPresent - # image: golang:1.7.5 - # command: - # - bash - # - "-c" - # - | - # set -ex - # go get github.com/tendermint/merkleeyes/cmd/merkleeyes - # rm -f /socks/data.sock # remove old socket - # merkleeyes server --address="unix:///socks/data.sock" - # volumeMounts: - # - name: socksdir - # mountPath: /socks - - - name: pub-key - imagePullPolicy: IfNotPresent - image: nginx:1.11.9 - resources: - requests: - cpu: 10m - memory: 12Mi - limits: - cpu: 20m - memory: 24Mi - ports: - - containerPort: 80 - name: pub-key - command: - - bash - - "-c" - - | - set -ex - # fixes 403 Permission Denied (open() "/tendermint/pub_key.json" failed (13: Permission denied)) - # => we cannot serve from /tendermint, so we copy the file - mkdir -p /usr/share/nginx - cp /tendermint/pub_key.json /usr/share/nginx/pub_key.json - nginx -g "daemon off;" - volumeMounts: - - name: tmdir - mountPath: /tendermint - - mountPath: /etc/nginx/conf.d/pub_key.conf - name: configdir - subPath: pub_key_nginx.conf - - volumes: - - name: configdir - configMap: - name: tm-config - - name: socksdir - emptyDir: {} - - volumeClaimTemplates: - - metadata: - name: tmdir - annotations: - volume.alpha.kubernetes.io/storage-class: anything - spec: - accessModes: ["ReadWriteOnce"] - resources: - requests: - storage: 2Gi diff --git a/tools/mintnet-kubernetes/assets/gce1.png b/tools/mintnet-kubernetes/assets/gce1.png deleted file mode 100644 index 3bf3ad005..000000000 Binary files a/tools/mintnet-kubernetes/assets/gce1.png and /dev/null differ diff --git a/tools/mintnet-kubernetes/assets/gce2.png b/tools/mintnet-kubernetes/assets/gce2.png deleted file mode 100644 index 358dcc04b..000000000 Binary files a/tools/mintnet-kubernetes/assets/gce2.png and /dev/null differ diff --git a/tools/mintnet-kubernetes/assets/statefulset.png b/tools/mintnet-kubernetes/assets/statefulset.png deleted file mode 100644 index ac68d22b7..000000000 Binary files a/tools/mintnet-kubernetes/assets/statefulset.png and /dev/null differ diff --git a/tools/mintnet-kubernetes/assets/t_plus_k.png b/tools/mintnet-kubernetes/assets/t_plus_k.png deleted file mode 100644 index bee9fe56e..000000000 Binary files a/tools/mintnet-kubernetes/assets/t_plus_k.png and /dev/null differ diff --git a/tools/mintnet-kubernetes/examples/counter/Makefile b/tools/mintnet-kubernetes/examples/counter/Makefile deleted file mode 100644 index 6d54d57d6..000000000 --- a/tools/mintnet-kubernetes/examples/counter/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -create: - @echo "==> Creating deployment" - @kubectl create -f app.yaml - -destroy: - @echo "==> Destroying deployment" - @kubectl delete -f app.yaml - @kubectl delete pvc -l app=tm - -.PHONY: create destroy diff --git a/tools/mintnet-kubernetes/examples/counter/app.yaml b/tools/mintnet-kubernetes/examples/counter/app.yaml deleted file mode 100644 index 4565f9764..000000000 --- a/tools/mintnet-kubernetes/examples/counter/app.yaml +++ /dev/null @@ -1,214 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" - name: counter - labels: - app: counter -spec: - ports: - - port: 26656 - name: p2p - - port: 26657 - name: rpc - clusterIP: None - selector: - app: tm ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: tm-config -data: - seeds: "tm-0,tm-1,tm-2,tm-3" - validators: "tm-0,tm-1,tm-2,tm-3" - validator.power: "10" - genesis.json: |- - { - "genesis_time": "2016-02-05T23:17:31.164Z", - "chain_id": "chain-B5XXm5", - "validators": [], - "app_hash": "" - } - pub_key_nginx.conf: |- - server { - listen 80 default_server; - listen [::]:80 default_server ipv6only=on; - location /pub_key.json { root /usr/share/nginx/; } - } ---- -apiVersion: policy/v1beta1 -kind: PodDisruptionBudget -metadata: - name: tm-budget -spec: - selector: - matchLabels: - app: tm - minAvailable: 2 ---- -apiVersion: apps/v1beta1 -kind: StatefulSet -metadata: - name: tm -spec: - serviceName: counter - replicas: 4 - template: - metadata: - labels: - app: tm - annotations: - pod.beta.kubernetes.io/init-containers: '[{ - "name": "tm-gen-validator", - "image": "tendermint/tendermint:0.10.0", - "imagePullPolicy": "IfNotPresent", - "command": ["bash", "-c", " - set -ex\n - if [ ! -f /tendermint/priv_validator.json ]; then\n - tendermint gen_validator > /tendermint/priv_validator.json\n - # pub_key.json will be served by pub-key container\n - cat /tendermint/priv_validator.json | jq \".pub_key\" > /tendermint/pub_key.json\n - fi\n - "], - "volumeMounts": [ - {"name": "tmdir", "mountPath": "/tendermint"} - ] - }]' - spec: - containers: - - name: tm - imagePullPolicy: IfNotPresent - image: tendermint/tendermint:0.10.0 - ports: - - containerPort: 26656 - name: p2p - - containerPort: 26657 - name: rpc - env: - - name: SEEDS - valueFrom: - configMapKeyRef: - name: tm-config - key: seeds - - name: VALIDATOR_POWER - valueFrom: - configMapKeyRef: - name: tm-config - key: validator.power - - name: VALIDATORS - valueFrom: - configMapKeyRef: - name: tm-config - key: validators - - name: TMHOME - value: /tendermint - command: - - bash - - "-c" - - | - set -ex - - # copy template - cp /etc/tendermint/genesis.json /tendermint/genesis.json - - # fill genesis file with validators - IFS=',' read -ra VALS_ARR <<< "$VALIDATORS" - fqdn_suffix=$(hostname -f | sed 's#[^.]*\.\(\)#\1#') - for v in "${VALS_ARR[@]}"; do - # wait until validator generates priv/pub key pair - set +e - - curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null - ERR=$? - while [ "$ERR" != 0 ]; do - sleep 5 - curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null - ERR=$? - done - set -e - - # add validator to genesis file along with its pub_key - curl -s "http://$v.$fqdn_suffix/pub_key.json" | jq ". as \$k | {pub_key: \$k, amount: $VALIDATOR_POWER, name: \"$v\"}" > pub_validator.json - cat /tendermint/genesis.json | jq ".validators |= .+ [$(cat pub_validator.json)]" > tmpgenesis && mv tmpgenesis /tendermint/genesis.json - rm pub_validator.json - done - - # construct seeds - IFS=',' read -ra SEEDS_ARR <<< "$SEEDS" - seeds=() - for s in "${SEEDS_ARR[@]}"; do - seeds+=("$s.$fqdn_suffix:26656") - done - seeds=$(IFS=','; echo "${seeds[*]}") - - tendermint node --p2p.seeds="$seeds" --moniker="`hostname`" --proxy_app="unix:///socks/app.sock" - volumeMounts: - - name: tmdir - mountPath: /tendermint - - mountPath: /etc/tendermint/genesis.json - name: tmconfigdir - subPath: genesis.json - - name: socksdir - mountPath: /socks - - - name: app - imagePullPolicy: IfNotPresent - image: golang:latest - command: - - bash - - "-c" - - | - set -ex - - go get github.com/tendermint/tendermint/abci/cmd/abci-cli - - rm -f /socks/app.sock # remove old socket - - abci-cli counter --serial=true --address="unix:///socks/app.sock" - volumeMounts: - - name: socksdir - mountPath: /socks - - - name: pub-key - imagePullPolicy: IfNotPresent - image: nginx:latest - ports: - - containerPort: 80 - name: pub-key - command: - - bash - - "-c" - - | - set -ex - # fixes 403 Permission Denied (open() "/tendermint/pub_key.json" failed (13: Permission denied)) - # => we cannot serve from /tendermint, so we copy the file - mkdir -p /usr/share/nginx - cp /tendermint/pub_key.json /usr/share/nginx/pub_key.json - nginx -g "daemon off;" - volumeMounts: - - name: tmdir - mountPath: /tendermint - - mountPath: /etc/nginx/conf.d/pub_key.conf - name: tmconfigdir - subPath: pub_key_nginx.conf - - volumes: - - name: tmconfigdir - configMap: - name: tm-config - - name: socksdir - emptyDir: {} - - volumeClaimTemplates: - - metadata: - name: tmdir - annotations: - volume.alpha.kubernetes.io/storage-class: anything - spec: - accessModes: ["ReadWriteOnce"] - resources: - requests: - storage: 2Gi diff --git a/tools/mintnet-kubernetes/examples/dummy/Makefile b/tools/mintnet-kubernetes/examples/dummy/Makefile deleted file mode 100644 index 825487fcd..000000000 --- a/tools/mintnet-kubernetes/examples/dummy/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -create: - @echo "==> Creating deployment" - @kubectl create -f app.yaml - @echo "==> Waiting 10s until it is probably ready" - @sleep 10 - @echo "==> Creating monitor and transacter pods" - @kubectl create -f tm-monitor-pod.yaml - @kubectl create -f transacter-pod.yaml - -destroy: - @echo "==> Destroying deployment" - @kubectl delete -f transacter-pod.yaml - @kubectl delete -f tm-monitor-pod.yaml - @kubectl delete -f app.yaml - @kubectl delete pvc -l app=tm - -.PHONY: create destroy diff --git a/tools/mintnet-kubernetes/examples/dummy/app.yaml b/tools/mintnet-kubernetes/examples/dummy/app.yaml deleted file mode 100644 index 5413bd501..000000000 --- a/tools/mintnet-kubernetes/examples/dummy/app.yaml +++ /dev/null @@ -1,196 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" - name: dummy - labels: - app: dummy -spec: - ports: - - port: 26656 - name: p2p - - port: 26657 - name: rpc - clusterIP: None - selector: - app: tm ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: tm-config -data: - seeds: "tm-0,tm-1,tm-2,tm-3" - validators: "tm-0,tm-1,tm-2,tm-3" - validator.power: "10" - genesis.json: |- - { - "genesis_time": "2016-02-05T23:17:31.164Z", - "chain_id": "chain-B5XXm5", - "validators": [], - "app_hash": "" - } - pub_key_nginx.conf: |- - server { - listen 80 default_server; - listen [::]:80 default_server ipv6only=on; - location /pub_key.json { root /usr/share/nginx/; } - } ---- -apiVersion: policy/v1beta1 -kind: PodDisruptionBudget -metadata: - name: tm-budget -spec: - selector: - matchLabels: - app: tm - minAvailable: 2 ---- -apiVersion: apps/v1beta1 -kind: StatefulSet -metadata: - name: tm -spec: - serviceName: dummy - replicas: 4 - template: - metadata: - labels: - app: tm - annotations: - pod.beta.kubernetes.io/init-containers: '[{ - "name": "tm-gen-validator", - "image": "tendermint/tendermint:0.10.0", - "imagePullPolicy": "IfNotPresent", - "command": ["bash", "-c", " - set -ex\n - if [ ! -f /tendermint/priv_validator.json ]; then\n - tendermint gen_validator > /tendermint/priv_validator.json\n - # pub_key.json will be served by pub-key container\n - cat /tendermint/priv_validator.json | jq \".pub_key\" > /tendermint/pub_key.json\n - fi\n - "], - "volumeMounts": [ - {"name": "tmdir", "mountPath": "/tendermint"} - ] - }]' - spec: - containers: - - name: tm - imagePullPolicy: IfNotPresent - image: tendermint/tendermint:0.10.0 - ports: - - containerPort: 26656 - name: p2p - - containerPort: 26657 - name: rpc - env: - - name: SEEDS - valueFrom: - configMapKeyRef: - name: tm-config - key: seeds - - name: VALIDATOR_POWER - valueFrom: - configMapKeyRef: - name: tm-config - key: validator.power - - name: VALIDATORS - valueFrom: - configMapKeyRef: - name: tm-config - key: validators - - name: TMHOME - value: /tendermint - command: - - bash - - "-c" - - | - set -ex - - # copy template - cp /etc/tendermint/genesis.json /tendermint/genesis.json - - # fill genesis file with validators - IFS=',' read -ra VALS_ARR <<< "$VALIDATORS" - fqdn_suffix=$(hostname -f | sed 's#[^.]*\.\(\)#\1#') - for v in "${VALS_ARR[@]}"; do - # wait until validator generates priv/pub key pair - set +e - - curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null - ERR=$? - while [ "$ERR" != 0 ]; do - sleep 5 - curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null - ERR=$? - done - set -e - - # add validator to genesis file along with its pub_key - curl -s "http://$v.$fqdn_suffix/pub_key.json" | jq ". as \$k | {pub_key: \$k, amount: $VALIDATOR_POWER, name: \"$v\"}" > pub_validator.json - cat /tendermint/genesis.json | jq ".validators |= .+ [$(cat pub_validator.json)]" > tmpgenesis && mv tmpgenesis /tendermint/genesis.json - rm pub_validator.json - done - - # construct seeds - IFS=',' read -ra SEEDS_ARR <<< "$SEEDS" - seeds=() - for s in "${SEEDS_ARR[@]}"; do - seeds+=("$s.$fqdn_suffix:26656") - done - seeds=$(IFS=','; echo "${seeds[*]}") - - tendermint node --p2p.seeds="$seeds" --moniker="`hostname`" --proxy_app="dummy" - volumeMounts: - - name: tmdir - mountPath: /tendermint - - mountPath: /etc/tendermint/genesis.json - name: tmconfigdir - subPath: genesis.json - - name: socksdir - mountPath: /socks - - - name: pub-key - imagePullPolicy: IfNotPresent - image: nginx:latest - ports: - - containerPort: 80 - name: pub-key - command: - - bash - - "-c" - - | - set -ex - # fixes 403 Permission Denied (open() "/tendermint/pub_key.json" failed (13: Permission denied)) - # => we cannot serve from /tendermint, so we copy the file - mkdir -p /usr/share/nginx - cp /tendermint/pub_key.json /usr/share/nginx/pub_key.json - nginx -g "daemon off;" - volumeMounts: - - name: tmdir - mountPath: /tendermint - - mountPath: /etc/nginx/conf.d/pub_key.conf - name: tmconfigdir - subPath: pub_key_nginx.conf - - volumes: - - name: tmconfigdir - configMap: - name: tm-config - - name: socksdir - emptyDir: {} - - volumeClaimTemplates: - - metadata: - name: tmdir - annotations: - volume.alpha.kubernetes.io/storage-class: anything - spec: - accessModes: ["ReadWriteOnce"] - resources: - requests: - storage: 2Gi diff --git a/tools/mintnet-kubernetes/examples/dummy/tm-monitor-pod.yaml b/tools/mintnet-kubernetes/examples/dummy/tm-monitor-pod.yaml deleted file mode 100644 index fb0bf7236..000000000 --- a/tools/mintnet-kubernetes/examples/dummy/tm-monitor-pod.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -apiVersion: v1 -kind: Pod -metadata: - name: monitor -spec: - containers: - - name: monitor - image: tendermint/monitor - args: ["-listen-addr=tcp://0.0.0.0:26670", "tm-0.dummy:26657,tm-1.dummy:26657,tm-2.dummy:26657,tm-3.dummy:26657"] - ports: - - containerPort: 26670 - name: rpc diff --git a/tools/mintnet-kubernetes/examples/dummy/transacter-pod.yaml b/tools/mintnet-kubernetes/examples/dummy/transacter-pod.yaml deleted file mode 100644 index 6598e2a8b..000000000 --- a/tools/mintnet-kubernetes/examples/dummy/transacter-pod.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -apiVersion: v1 -kind: Pod -metadata: - name: transacter -spec: - containers: - - name: transacter - image: tendermint/transacter - command: - - bash - - "-c" - - | - set -ex - while true - do - ./transact 100 "tm-0.dummy:26657" - sleep 1 - done diff --git a/types/block.go b/types/block.go index da0e78cf2..f9d1879f0 100644 --- a/types/block.go +++ b/types/block.go @@ -137,22 +137,22 @@ func (b *Block) Hash() tmbytes.HexBytes { // MakePartSet returns a PartSet containing parts of a serialized block. // This is the form in which the block is gossipped to peers. // CONTRACT: partSize is greater than zero. -func (b *Block) MakePartSet(partSize uint32) *PartSet { +func (b *Block) MakePartSet(partSize uint32) (*PartSet, error) { if b == nil { - return nil + return nil, errors.New("nil block") } b.mtx.Lock() defer b.mtx.Unlock() pbb, err := b.ToProto() if err != nil { - panic(err) + return nil, err } bz, err := proto.Marshal(pbb) if err != nil { - panic(err) + return nil, err } - return NewPartSetFromData(bz, partSize) + return NewPartSetFromData(bz, partSize), nil } // HashesTo is a convenience function that checks if a block hashes to the given argument. @@ -509,7 +509,8 @@ func (h *Header) StringIndented(indent string) string { indent, h.LastResultsHash, indent, h.EvidenceHash, indent, h.ProposerAddress, - indent, h.Hash()) + indent, h.Hash(), + ) } // ToProto converts Header to protobuf diff --git a/types/block_test.go b/types/block_test.go index 2355cb0f1..30f3bfbdb 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -110,15 +110,20 @@ func TestBlockHash(t *testing.T) { } func TestBlockMakePartSet(t *testing.T) { - assert.Nil(t, (*Block)(nil).MakePartSet(2)) + bps, err := (*Block)(nil).MakePartSet(2) + assert.Error(t, err) + assert.Nil(t, bps) - partSet := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).MakePartSet(1024) + partSet, err := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).MakePartSet(1024) + require.NoError(t, err) assert.NotNil(t, partSet) assert.EqualValues(t, 1, partSet.Total()) } func TestBlockMakePartSetWithEvidence(t *testing.T) { - assert.Nil(t, (*Block)(nil).MakePartSet(2)) + bps, err := (*Block)(nil).MakePartSet(2) + assert.Error(t, err) + assert.Nil(t, bps) lastID := makeBlockIDRandom() h := int64(3) @@ -130,7 +135,9 @@ func TestBlockMakePartSetWithEvidence(t *testing.T) { ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") evList := []Evidence{ev} - partSet := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(512) + partSet, err := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(512) + require.NoError(t, err) + assert.NotNil(t, partSet) assert.EqualValues(t, 4, partSet.Total()) } diff --git a/types/evidence_test.go b/types/evidence_test.go index 946373aad..959eb5086 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -245,9 +245,8 @@ func makeVote( vpb := v.ToProto() err = val.SignVote(chainID, vpb) - if err != nil { - panic(err) - } + require.NoError(t, err) + v.Signature = vpb.Signature return v } diff --git a/types/tx.go b/types/tx.go index 5bfc4f925..ade9c94e4 100644 --- a/types/tx.go +++ b/types/tx.go @@ -5,7 +5,9 @@ import ( "crypto/sha256" "errors" "fmt" + "sort" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/tmhash" tmbytes "github.com/tendermint/tendermint/libs/bytes" @@ -45,13 +47,8 @@ type Txs []Tx // Hash returns the Merkle root hash of the transaction hashes. // i.e. the leaves of the tree are the hashes of the txs. func (txs Txs) Hash() []byte { - // These allocations will be removed once Txs is switched to [][]byte, - // ref #2603. This is because golang does not allow type casting slices without unsafe - txBzs := make([][]byte, len(txs)) - for i := 0; i < len(txs); i++ { - txBzs[i] = txs[i].Hash() - } - return merkle.HashFromByteSlices(txBzs) + hl := txs.hashList() + return merkle.HashFromByteSlices(hl) } // Index returns the index of this transaction in the list, or -1 if not found @@ -74,16 +71,9 @@ func (txs Txs) IndexByHash(hash []byte) int { return -1 } -// Proof returns a simple merkle proof for this node. -// Panics if i < 0 or i >= len(txs) -// TODO: optimize this! func (txs Txs) Proof(i int) TxProof { - l := len(txs) - bzs := make([][]byte, l) - for i := 0; i < l; i++ { - bzs[i] = txs[i].Hash() - } - root, proofs := merkle.ProofsFromByteSlices(bzs) + hl := txs.hashList() + root, proofs := merkle.ProofsFromByteSlices(hl) return TxProof{ RootHash: root, @@ -92,11 +82,23 @@ func (txs Txs) Proof(i int) TxProof { } } +func (txs Txs) hashList() [][]byte { + hl := make([][]byte, len(txs)) + for i := 0; i < len(txs); i++ { + hl[i] = txs[i].Hash() + } + return hl +} + +// Txs is a slice of transactions. Sorting a Txs value orders the transactions +// lexicographically. +func (txs Txs) Len() int { return len(txs) } +func (txs Txs) Swap(i, j int) { txs[i], txs[j] = txs[j], txs[i] } +func (txs Txs) Less(i, j int) bool { + return bytes.Compare(txs[i], txs[j]) == -1 +} + // ToSliceOfBytes converts a Txs to slice of byte slices. -// -// NOTE: This method should become obsolete once Txs is switched to [][]byte. -// ref: #2603 -// TODO This function is to disappear when TxRecord is introduced func (txs Txs) ToSliceOfBytes() [][]byte { txBzs := make([][]byte, len(txs)) for i := 0; i < len(txs); i++ { @@ -105,13 +107,179 @@ func (txs Txs) ToSliceOfBytes() [][]byte { return txBzs } -// ToTxs converts a raw slice of byte slices into a Txs type. -func ToTxs(txs [][]byte) Txs { - txBzs := make(Txs, len(txs)) - for i := 0; i < len(txs); i++ { - txBzs[i] = txs[i] +// TxRecordSet contains indexes into an underlying set of transactions. +// These indexes are useful for validating and working with a list of TxRecords +// from the PrepareProposal response. +// +// Only one copy of the original data is referenced by all of the indexes but a +// transaction may appear in multiple indexes. +type TxRecordSet struct { + // all holds the complete list of all transactions from the original list of + // TxRecords. + all Txs + + // included is an index of the transactions that will be included in the block + // and is constructed from the list of both added and unmodified transactions. + // included maintains the original order that the transactions were present + // in the list of TxRecords. + included Txs + + // added, unmodified, removed, and unknown are indexes for each of the actions + // that may be supplied with a transaction. + // + // Because each transaction only has one action, it can be referenced by + // at most 3 indexes in this data structure: the action-specific index, the + // included index, and the all index. + added Txs + unmodified Txs + removed Txs + unknown Txs +} + +// NewTxRecordSet constructs a new set from the given transaction records. +// The contents of the input transactions are shared by the set, and must not +// be modified during the lifetime of the set. +func NewTxRecordSet(trs []*abci.TxRecord) TxRecordSet { + txrSet := TxRecordSet{ + all: make([]Tx, len(trs)), } - return txBzs + for i, tr := range trs { + + txrSet.all[i] = Tx(tr.Tx) + + // The following set of assignments do not allocate new []byte, they create + // pointers to the already allocated slice. + switch tr.GetAction() { + case abci.TxRecord_UNKNOWN: + txrSet.unknown = append(txrSet.unknown, txrSet.all[i]) + case abci.TxRecord_UNMODIFIED: + txrSet.unmodified = append(txrSet.unmodified, txrSet.all[i]) + txrSet.included = append(txrSet.included, txrSet.all[i]) + case abci.TxRecord_ADDED: + txrSet.added = append(txrSet.added, txrSet.all[i]) + txrSet.included = append(txrSet.included, txrSet.all[i]) + case abci.TxRecord_REMOVED: + txrSet.removed = append(txrSet.removed, txrSet.all[i]) + } + } + return txrSet +} + +// IncludedTxs returns the transactions marked for inclusion in a block. This +// list maintains the order that the transactions were included in the list of +// TxRecords that were used to construct the TxRecordSet. +func (t TxRecordSet) IncludedTxs() []Tx { + return t.included +} + +// RemovedTxs returns the transactions marked for removal by the application. +func (t TxRecordSet) RemovedTxs() []Tx { + return t.removed +} + +// Validate checks that the record set was correctly constructed from the original +// list of transactions. +func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error { + if len(t.unknown) > 0 { + return fmt.Errorf("%d transactions marked unknown (first unknown hash: %x)", len(t.unknown), t.unknown[0].Hash()) + } + + // The following validation logic performs a set of sorts on the data in the TxRecordSet indexes. + // It sorts the original transaction list, otxs, once. + // It sorts the new transaction list twice: once when sorting 'all', the total list, + // and once by sorting the set of the added, removed, and unmodified transactions indexes, + // which, when combined, comprise the complete list of modified transactions. + // + // Each of the added, removed, and unmodified indices is then iterated and once + // and each value index is checked against the sorted original list for containment. + // Asymptotically, this yields a total runtime of O(N*log(N) + 2*M*log(M) + M*log(N)). + // in the input size of the original list, N, and the input size of the new list, M, respectively. + // Performance gains are likely possible, but this was preferred for readability and maintainability. + + // Sort a copy of the complete transaction slice so we can check for + // duplication. The copy is so we do not change the original ordering. + // Only the slices are copied, the transaction contents are shared. + allCopy := sortedCopy(t.all) + + for i, cur := range allCopy { + // allCopy is sorted, so any duplicated data will be adjacent. + if i+1 < len(allCopy) && bytes.Equal(cur, allCopy[i+1]) { + return fmt.Errorf("found duplicate transaction with hash: %x", cur.Hash()) + } + } + + // create copies of each of the action-specific indexes so that order of the original + // indexes can be preserved. + addedCopy := sortedCopy(t.added) + removedCopy := sortedCopy(t.removed) + unmodifiedCopy := sortedCopy(t.unmodified) + + var size int64 + for _, cur := range append(unmodifiedCopy, addedCopy...) { + size += int64(len(cur)) + if size > maxSizeBytes { + return fmt.Errorf("transaction data size exceeds maximum %d", maxSizeBytes) + } + } + + // make a defensive copy of otxs so that the order of + // the caller's data is not altered. + otxsCopy := sortedCopy(otxs) + + if ix, ok := containsAll(otxsCopy, unmodifiedCopy); !ok { + return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", unmodifiedCopy[ix].Hash()) + } + + if ix, ok := containsAll(otxsCopy, removedCopy); !ok { + return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", removedCopy[ix].Hash()) + } + if ix, ok := containsAny(otxsCopy, addedCopy); ok { + return fmt.Errorf("existing transaction incorrectly marked as added, transaction hash: %x", addedCopy[ix].Hash()) + } + return nil +} + +func sortedCopy(txs Txs) Txs { + cp := make(Txs, len(txs)) + copy(cp, txs) + sort.Sort(cp) + return cp +} + +// containsAny checks that list a contains one of the transactions in list +// b. If a match is found, the index in b of the matching transaction is returned. +// Both lists must be sorted. +func containsAny(a, b []Tx) (int, bool) { + for i, cur := range b { + if _, ok := contains(a, cur); ok { + return i, true + } + } + return -1, false +} + +// containsAll checks that super contains all of the transactions in the sub +// list. If not all values in sub are present in super, the index in sub of the +// first Tx absent from super is returned. +func containsAll(super, sub Txs) (int, bool) { + for i, cur := range sub { + if _, ok := contains(super, cur); !ok { + return i, false + } + } + return -1, true +} + +// contains checks that the sorted list, set contains elem. If set does contain elem, then the +// index in set of elem is returned. +func contains(set []Tx, elem Tx) (int, bool) { + n := sort.Search(len(set), func(i int) bool { + return bytes.Compare(elem, set[i]) <= 0 + }) + if n == len(set) || !bytes.Equal(elem, set[n]) { + return -1, false + } + return n, true } // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. diff --git a/types/tx_test.go b/types/tx_test.go index 0ee308ced..a84b0bf36 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -2,11 +2,13 @@ package types import ( "bytes" + "math/rand" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" tmrand "github.com/tendermint/tendermint/libs/rand" ctest "github.com/tendermint/tendermint/libs/test" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -20,11 +22,6 @@ func makeTxs(cnt, size int) Txs { return txs } -func randInt(low, high int) int { - off := tmrand.Int() % (high - low) - return low + off -} - func TestTxIndex(t *testing.T) { for i := 0; i < 20; i++ { txs := makeTxs(15, 60) @@ -51,6 +48,179 @@ func TestTxIndexByHash(t *testing.T) { } } +func TestValidateTxRecordSet(t *testing.T) { + t.Run("should error on total transaction size exceeding max data size", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{6, 7, 8, 9, 10}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(9, []Tx{}) + require.Error(t, err) + }) + t.Run("should not error on removed transaction size exceeding max data size", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{6, 7, 8, 9}), + }, + { + Action: abci.TxRecord_REMOVED, + Tx: Tx([]byte{10}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(9, []Tx{[]byte{10}}) + require.NoError(t, err) + }) + t.Run("should error on duplicate transactions with the same action", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{100}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{200}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("should error on duplicate transactions with mixed actions", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{100}), + }, + { + Action: abci.TxRecord_REMOVED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{200}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("should error on new transactions marked UNMODIFIED", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_UNMODIFIED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("should error on new transactions marked REMOVED", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_REMOVED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("should error on existing transaction marked as ADDED", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{5, 4, 3, 2, 1}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{6}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{{0}, {1, 2, 3, 4, 5}}) + require.Error(t, err) + }) + t.Run("should error if any transaction marked as UNKNOWN", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_UNKNOWN, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("TxRecordSet preserves order", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{100}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{99}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{55}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{12}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{66}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{9}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{17}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.NoError(t, err) + for i, tx := range txrSet.IncludedTxs() { + require.Equal(t, Tx(trs[i].Tx), tx) + } + }) +} + func TestValidTxProof(t *testing.T) { cases := []struct { txs Txs @@ -149,3 +319,7 @@ func assertBadProof(t *testing.T, root []byte, bad []byte, good TxProof) { } } } + +func randInt(low, high int) int { + return rand.Intn(high-low) + low +} diff --git a/types/vote.go b/types/vote.go index 7b841c28a..02b3cad3d 100644 --- a/types/vote.go +++ b/types/vote.go @@ -220,6 +220,22 @@ func (vote *Vote) ToProto() *tmproto.Vote { } } +func VotesToProto(votes []*Vote) []*tmproto.Vote { + if votes == nil { + return nil + } + + res := make([]*tmproto.Vote, 0, len(votes)) + for _, vote := range votes { + v := vote.ToProto() + // protobuf crashes when serializing "repeated" fields with nil elements + if v != nil { + res = append(res, v) + } + } + return res +} + // FromProto converts a proto generetad type to a handwritten type // return type, nil if everything converts safely, otherwise nil, error func VoteFromProto(pv *tmproto.Vote) (*Vote, error) { diff --git a/types/vote_set.go b/types/vote_set.go index abdc18e61..829b54b53 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -226,6 +226,13 @@ func (voteSet *VoteSet) getVote(valIndex int32, blockKey string) (vote *Vote, ok return nil, false } +func (voteSet *VoteSet) GetVotes() []*Vote { + if voteSet == nil { + return nil + } + return voteSet.votes +} + // Assumes signature is valid. // If conflicting vote exists, returns it. func (voteSet *VoteSet) addVerifiedVote( @@ -627,6 +634,7 @@ func (voteSet *VoteSet) MakeCommit() *Commit { if commitSig.ForBlock() && !v.BlockID.Equals(*voteSet.maj23) { commitSig = NewCommitSigAbsent() } + commitSigs[i] = commitSig } diff --git a/version/version.go b/version/version.go index 79295b5a7..18d203148 100644 --- a/version/version.go +++ b/version/version.go @@ -15,7 +15,7 @@ const ( ) var ( - // P2PProtocol versions all p2p behaviour and msgs. + // P2PProtocol versions all p2p behaviur and msgs. // This includes proposer selection. P2PProtocol uint64 = 8