From 61619ab072858838fb4833e99d9292b6bcb76f95 Mon Sep 17 00:00:00 2001 From: Sergio Mena Date: Wed, 3 Aug 2022 11:06:54 +0200 Subject: [PATCH 1/4] Update `feature/abci++ppp` branch with latest infra changes in `main` (#9157) * Update CODEOWNERS to use teams (#9129) * Update CODEOWNERS to use teams Update the `CODEOWNERS` file to use the @tendermint/tendermint-engineering and @tendermint/tendermint-research teams as opposed to adding people one by one. This makes repository administration somewhat easier to manage, especially when onboarding/offboarding people. Signed-off-by: Thane Thomson * Add Ethan as superuser Signed-off-by: Thane Thomson * Prepare `main` to become new default branch (#9095) * Update Makefile with changes from #7372 Signed-off-by: Thane Thomson * Sync main GitHub config with master and update Signed-off-by: Thane Thomson * Remove unnecesary dot folders Signed-off-by: Thane Thomson * Sync dotfiles Signed-off-by: Thane Thomson * Remove unused Jepsen tests for now Signed-off-by: Thane Thomson * tools: remove k8s (#6625) Remove mintnet as discussed on team call. closes #1941 * Restore nightly fuzz testing of P2P addrbook and pex Signed-off-by: Thane Thomson * Fix YAML lints Signed-off-by: Thane Thomson * Fix YAML formatting nits Signed-off-by: Thane Thomson * More YAML nits Signed-off-by: Thane Thomson * github: fix linter configuration errors and occluded errors (#6400) * Minor fixes to OpenAPI spec to sync with structs on main Signed-off-by: Thane Thomson * Remove .github/auto-comment.yml - does not appear to be used Signed-off-by: Thane Thomson * Add issue config with link to discussions Signed-off-by: Thane Thomson * Adjust issue/PR templates to suit current process Signed-off-by: Thane Thomson * Remove unused RC branch config from release workflow Signed-off-by: Thane Thomson * Fix wildcard matching in build jobs config Signed-off-by: Thane Thomson * Document markdownlint config Signed-off-by: Thane Thomson * Restore manual E2E test group config Signed-off-by: Thane Thomson * Document linter workflow with local execution instructions Signed-off-by: Thane Thomson * Document and fix minor nit in Super-Linter markdownlint config Signed-off-by: Thane Thomson * Update .github/ISSUE_TEMPLATE/bug-report.md Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update pull request template to add language around discussions/issues Signed-off-by: Thane Thomson * .golangci.yml: Deleted commented-out lines Signed-off-by: Thane Thomson * ci: Drop "-2" from e2e-nightly-fail workflow Signed-off-by: Thane Thomson * Address triviality concern in PR template Signed-off-by: Thane Thomson Co-authored-by: Marko Co-authored-by: Sam Kleinman Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> Co-authored-by: Thane Thomson Co-authored-by: Marko Co-authored-by: Sam Kleinman Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> --- .circleci/config.yml | 168 ---------- .github/CODEOWNERS | 4 +- .github/ISSUE_TEMPLATE/bug-report.md | 11 +- .github/ISSUE_TEMPLATE/config.yml | 5 + .github/ISSUE_TEMPLATE/feature-request.md | 11 +- .github/ISSUE_TEMPLATE/proposal.md | 28 ++ .github/PULL_REQUEST_TEMPLATE.md | 33 +- .github/auto-comment.yml | 16 - .github/codecov.yml | 25 ++ .github/dependabot.yml | 51 +++ .github/issue_template.md | 6 + .github/linters/markdownlint.yml | 15 + .github/linters/yaml-lint.yml | 9 + .github/mergify.yml | 14 +- .github/workflows/build.yml | 82 +++++ .github/workflows/coverage.yml | 123 -------- .github/workflows/docker.yml | 21 +- .github/workflows/docs-deployment.yml | 62 ++++ .github/workflows/docs-toc.yml | 21 ++ .github/workflows/e2e-manual.yml | 5 +- .github/workflows/e2e-nightly-34x.yml | 32 +- ...ightly-master.yml => e2e-nightly-main.yml} | 38 +-- .github/workflows/e2e.yml | 16 +- .github/workflows/fuzz-nightly.yml | 18 +- .github/workflows/janitor.yml | 16 + .github/workflows/linkchecker.yml | 12 - .github/workflows/lint.yml | 22 +- .github/workflows/linter.yml | 12 +- .github/workflows/markdown-links.yml | 23 ++ .github/workflows/proto-lint.yml | 2 +- .github/workflows/proto.yml | 22 -- .github/workflows/release.yml | 18 +- .github/workflows/stale.yml | 6 +- .github/workflows/tests.yml | 142 +-------- .gitignore | 68 ++-- .golangci.yml | 30 +- .goreleaser.yml | 10 +- .markdownlint.yml | 11 +- .md-link-check.json | 6 + .mergify.yml | 10 - .vscode/settings.json | 8 - Makefile | 25 +- appveyor.yml | 10 +- docker-compose.yml | 4 +- networks/remote/ansible/config.yml | 1 - networks/remote/ansible/install.yml | 1 - networks/remote/ansible/logzio.yml | 1 - networks/remote/ansible/reset.yml | 2 - networks/remote/ansible/restart.yml | 1 - .../ansible/roles/config/tasks/main.yml | 3 +- .../ansible/roles/install/handlers/main.yml | 1 - .../ansible/roles/install/tasks/main.yml | 1 - .../ansible/roles/logzio/handlers/main.yml | 1 - .../ansible/roles/logzio/tasks/main.yml | 1 - .../remote/ansible/roles/start/tasks/main.yml | 1 - .../ansible/roles/status/tasks/main.yml | 1 - .../remote/ansible/roles/stop/tasks/main.yml | 1 - .../ansible/roles/unsafe_reset/tasks/main.yml | 1 - networks/remote/ansible/start.yml | 1 - networks/remote/ansible/status.yml | 1 - networks/remote/ansible/stop.yml | 1 - rpc/openapi/openapi.yaml | 37 ++- tools/mintnet-kubernetes/README.rst | 290 ------------------ tools/mintnet-kubernetes/app.template.yaml | 265 ---------------- tools/mintnet-kubernetes/assets/gce1.png | Bin 13143 -> 0 bytes tools/mintnet-kubernetes/assets/gce2.png | Bin 31246 -> 0 bytes .../mintnet-kubernetes/assets/statefulset.png | Bin 17367 -> 0 bytes tools/mintnet-kubernetes/assets/t_plus_k.png | Bin 18476 -> 0 bytes .../examples/counter/Makefile | 10 - .../examples/counter/app.yaml | 214 ------------- .../examples/dummy/Makefile | 17 - .../examples/dummy/app.yaml | 196 ------------ .../examples/dummy/tm-monitor-pod.yaml | 13 - .../examples/dummy/transacter-pod.yaml | 19 -- 74 files changed, 627 insertions(+), 1725 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/proposal.md delete mode 100644 .github/auto-comment.yml create mode 100644 .github/codecov.yml create mode 100644 .github/dependabot.yml create mode 100644 .github/issue_template.md create mode 100644 .github/linters/markdownlint.yml create mode 100644 .github/linters/yaml-lint.yml create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/coverage.yml create mode 100644 .github/workflows/docs-deployment.yml create mode 100644 .github/workflows/docs-toc.yml rename .github/workflows/{e2e-nightly-master.yml => e2e-nightly-main.yml} (60%) create mode 100644 .github/workflows/janitor.yml delete mode 100644 .github/workflows/linkchecker.yml create mode 100644 .github/workflows/markdown-links.yml delete mode 100644 .github/workflows/proto.yml create mode 100644 .md-link-check.json delete mode 100644 .mergify.yml delete mode 100644 .vscode/settings.json delete mode 100644 tools/mintnet-kubernetes/README.rst delete mode 100644 tools/mintnet-kubernetes/app.template.yaml delete mode 100644 tools/mintnet-kubernetes/assets/gce1.png delete mode 100644 tools/mintnet-kubernetes/assets/gce2.png delete mode 100644 tools/mintnet-kubernetes/assets/statefulset.png delete mode 100644 tools/mintnet-kubernetes/assets/t_plus_k.png delete mode 100644 tools/mintnet-kubernetes/examples/counter/Makefile delete mode 100644 tools/mintnet-kubernetes/examples/counter/app.yaml delete mode 100644 tools/mintnet-kubernetes/examples/dummy/Makefile delete mode 100644 tools/mintnet-kubernetes/examples/dummy/app.yaml delete mode 100644 tools/mintnet-kubernetes/examples/dummy/tm-monitor-pod.yaml delete mode 100644 tools/mintnet-kubernetes/examples/dummy/transacter-pod.yaml 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/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/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/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/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/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 3bf3ad005bfb3b13f80cdee45c6d633f8d08c480..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13143 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
  • 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 diff --git a/tools/mintnet-kubernetes/assets/gce2.png b/tools/mintnet-kubernetes/assets/gce2.png deleted file mode 100644 index 358dcc04b36585b1a891e47973b3dcc7ef5dbc1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31246 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 Dksn_w 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 bee9fe56e204436a43cd3ec0a9e3755b691d7d5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18476 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 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 From 2164883501c72400076a302dfb60c0afa6165a5e Mon Sep 17 00:00:00 2001 From: Sergio Mena Date: Wed, 3 Aug 2022 13:29:15 +0200 Subject: [PATCH 2/4] Old PrepareProposal and vote extension integration on feature/abci++ppp (#9117) * abci: PrepareProposal-VoteExtension integration [2nd try] (#7821) * PrepareProposal-VoteExtension integration (#6915) * make proto-gen * Fix protobuf crash in e2e nightly tests * Update types/vote.go Co-authored-by: M. J. Fromberger * Addressed @creachadair's comments Co-authored-by: mconcat Co-authored-by: M. J. Fromberger * Proto changes * make proto-gen * Fixed UTs * bump * lint * lint2 * lint3 * lint4 * lint5 * lint6 * no_lint Co-authored-by: mconcat Co-authored-by: M. J. Fromberger --- abci/types/types.pb.go | 430 +++++++++++++++++------------- behaviour/doc.go | 8 +- behaviour/peer_behaviour.go | 6 +- behaviour/reporter.go | 26 +- behaviour/reporter_test.go | 62 ++--- blockchain/v1/reactor.go | 4 +- blockchain/v2/processor_test.go | 2 +- blockchain/v2/reactor.go | 4 +- blockchain/v2/reactor_test.go | 4 +- blockchain/v2/scheduler_test.go | 2 +- cmd/tendermint/commands/init.go | 2 +- cmd/tendermint/commands/light.go | 2 +- config/config.go | 2 +- config/toml.go | 2 +- consensus/byzantine_test.go | 4 +- consensus/replay.go | 2 +- consensus/replay_test.go | 2 +- consensus/state.go | 8 +- libs/pubsub/pubsub.go | 2 +- libs/pubsub/subscription.go | 2 +- light/provider/http/http.go | 2 +- node/node_test.go | 4 +- p2p/netaddress.go | 2 +- p2p/pex/addrbook_test.go | 2 +- p2p/pex/pex_reactor.go | 2 +- p2p/transport.go | 4 +- proto/tendermint/abci/types.proto | 3 + rpc/client/interface.go | 2 +- rpc/client/local/local.go | 2 +- rpc/core/events.go | 4 +- rpc/core/mempool.go | 2 +- rpc/jsonrpc/server/ws_handler.go | 2 +- state/execution.go | 7 +- state/execution_test.go | 2 +- state/state_test.go | 2 +- statesync/syncer.go | 2 +- test/maverick/consensus/replay.go | 2 +- test/maverick/consensus/state.go | 6 +- types/block.go | 3 +- types/vote.go | 16 ++ types/vote_set.go | 4 + version/version.go | 2 +- 42 files changed, 378 insertions(+), 275 deletions(-) diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 54f4333ed..957a99c1c 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -1235,6 +1235,9 @@ type RequestPrepareProposal struct { 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"` + // votes includes all votes from the previous block. This contains vote extension data that can be used in proposal + // preparation. The votes here will then form the last commit that gets sent in the proposed block. + Votes []*types1.Vote `protobuf:"bytes,3,rep,name=votes,proto3" json:"votes,omitempty"` } func (m *RequestPrepareProposal) Reset() { *m = RequestPrepareProposal{} } @@ -1284,6 +1287,13 @@ func (m *RequestPrepareProposal) GetBlockDataSize() int64 { return 0 } +func (m *RequestPrepareProposal) GetVotes() []*types1.Vote { + if m != nil { + return m.Votes + } + return nil +} + type Response struct { // Types that are valid to be assigned to Value: // *Response_Exception @@ -3353,188 +3363,190 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 2894 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0xcd, 0x73, 0x23, 0xc5, - 0x15, 0xd7, 0xb7, 0x34, 0x4f, 0xd6, 0x87, 0x7b, 0x97, 0x5d, 0x31, 0xec, 0xda, 0xcb, 0x50, 0xc0, - 0xb2, 0x80, 0x1d, 0x4c, 0x41, 0x96, 0x40, 0x02, 0x96, 0x56, 0x8b, 0x8c, 0x8d, 0xed, 0x8c, 0xb5, - 0x4b, 0xbe, 0xd8, 0x61, 0xa4, 0x69, 0x4b, 0xc3, 0x4a, 0x33, 0xc3, 0x4c, 0xcb, 0xd8, 0x7b, 0x4c, - 0x25, 0x17, 0x72, 0xe1, 0x98, 0x0b, 0xff, 0x47, 0x0e, 0xa9, 0x5c, 0x72, 0xa1, 0x2a, 0x17, 0x8e, - 0x39, 0xa4, 0x48, 0x8a, 0x3d, 0xa4, 0x92, 0x7f, 0x20, 0xa7, 0x54, 0x52, 0xfd, 0x31, 0x5f, 0x92, - 0xc6, 0x92, 0x21, 0xb7, 0xdc, 0xba, 0x5f, 0xbf, 0xf7, 0x66, 0xba, 0xa7, 0xfb, 0xf7, 0x7e, 0xef, - 0xf5, 0xc0, 0x53, 0x04, 0x5b, 0x06, 0x76, 0xc7, 0xa6, 0x45, 0x36, 0xf5, 0x5e, 0xdf, 0xdc, 0x24, - 0x67, 0x0e, 0xf6, 0x36, 0x1c, 0xd7, 0x26, 0x36, 0xaa, 0x85, 0x83, 0x1b, 0x74, 0x50, 0xbe, 0x1e, - 0xd1, 0xee, 0xbb, 0x67, 0x0e, 0xb1, 0x37, 0x1d, 0xd7, 0xb6, 0x8f, 0xb9, 0xbe, 0x7c, 0x2d, 0x32, - 0xcc, 0xfc, 0x44, 0xbd, 0xc5, 0x46, 0x85, 0xf1, 0x43, 0x7c, 0xe6, 0x8f, 0x5e, 0x9f, 0xb1, 0x75, - 0x74, 0x57, 0x1f, 0xfb, 0xc3, 0xeb, 0x03, 0xdb, 0x1e, 0x8c, 0xf0, 0x26, 0xeb, 0xf5, 0x26, 0xc7, - 0x9b, 0xc4, 0x1c, 0x63, 0x8f, 0xe8, 0x63, 0x47, 0x28, 0x5c, 0x1e, 0xd8, 0x03, 0x9b, 0x35, 0x37, - 0x69, 0x8b, 0x4b, 0x95, 0xbf, 0x97, 0xa0, 0xa8, 0xe2, 0x4f, 0x26, 0xd8, 0x23, 0x68, 0x0b, 0x72, - 0xb8, 0x3f, 0xb4, 0x1b, 0xe9, 0x1b, 0xe9, 0x9b, 0xe5, 0xad, 0x6b, 0x1b, 0x53, 0x93, 0xdb, 0x10, - 0x7a, 0xed, 0xfe, 0xd0, 0xee, 0xa4, 0x54, 0xa6, 0x8b, 0x5e, 0x83, 0xfc, 0xf1, 0x68, 0xe2, 0x0d, - 0x1b, 0x19, 0x66, 0x74, 0x3d, 0xc9, 0xe8, 0x2e, 0x55, 0xea, 0xa4, 0x54, 0xae, 0x4d, 0x1f, 0x65, - 0x5a, 0xc7, 0x76, 0x23, 0x7b, 0xfe, 0xa3, 0x76, 0xac, 0x63, 0xf6, 0x28, 0xaa, 0x8b, 0x9a, 0x00, - 0x1e, 0x26, 0x9a, 0xed, 0x10, 0xd3, 0xb6, 0x1a, 0x39, 0x66, 0xf9, 0x74, 0x92, 0xe5, 0x11, 0x26, - 0x07, 0x4c, 0xb1, 0x93, 0x52, 0x25, 0xcf, 0xef, 0x50, 0x1f, 0xa6, 0x65, 0x12, 0xad, 0x3f, 0xd4, - 0x4d, 0xab, 0x91, 0x3f, 0xdf, 0xc7, 0x8e, 0x65, 0x92, 0x16, 0x55, 0xa4, 0x3e, 0x4c, 0xbf, 0x43, - 0xa7, 0xfc, 0xc9, 0x04, 0xbb, 0x67, 0x8d, 0xc2, 0xf9, 0x53, 0xfe, 0x31, 0x55, 0xa2, 0x53, 0x66, - 0xda, 0xa8, 0x0d, 0xe5, 0x1e, 0x1e, 0x98, 0x96, 0xd6, 0x1b, 0xd9, 0xfd, 0x87, 0x8d, 0x22, 0x33, - 0x56, 0x92, 0x8c, 0x9b, 0x54, 0xb5, 0x49, 0x35, 0x3b, 0x29, 0x15, 0x7a, 0x41, 0x0f, 0xbd, 0x05, - 0xa5, 0xfe, 0x10, 0xf7, 0x1f, 0x6a, 0xe4, 0xb4, 0x51, 0x62, 0x3e, 0xd6, 0x93, 0x7c, 0xb4, 0xa8, - 0x5e, 0xf7, 0xb4, 0x93, 0x52, 0x8b, 0x7d, 0xde, 0xa4, 0xf3, 0x37, 0xf0, 0xc8, 0x3c, 0xc1, 0x2e, - 0xb5, 0x97, 0xce, 0x9f, 0xff, 0x1d, 0xae, 0xc9, 0x3c, 0x48, 0x86, 0xdf, 0x41, 0x6f, 0x83, 0x84, - 0x2d, 0x43, 0x4c, 0x03, 0x98, 0x8b, 0x1b, 0x89, 0x7b, 0xc5, 0x32, 0xfc, 0x49, 0x94, 0xb0, 0x68, - 0xa3, 0xdb, 0x50, 0xe8, 0xdb, 0xe3, 0xb1, 0x49, 0x1a, 0x65, 0x66, 0xbd, 0x96, 0x38, 0x01, 0xa6, - 0xd5, 0x49, 0xa9, 0x42, 0x1f, 0xed, 0x43, 0x75, 0x64, 0x7a, 0x44, 0xf3, 0x2c, 0xdd, 0xf1, 0x86, - 0x36, 0xf1, 0x1a, 0x2b, 0xcc, 0xc3, 0xb3, 0x49, 0x1e, 0xf6, 0x4c, 0x8f, 0x1c, 0xf9, 0xca, 0x9d, - 0x94, 0x5a, 0x19, 0x45, 0x05, 0xd4, 0x9f, 0x7d, 0x7c, 0x8c, 0xdd, 0xc0, 0x61, 0xa3, 0x72, 0xbe, - 0xbf, 0x03, 0xaa, 0xed, 0xdb, 0x53, 0x7f, 0x76, 0x54, 0x80, 0x7e, 0x0e, 0x97, 0x46, 0xb6, 0x6e, - 0x04, 0xee, 0xb4, 0xfe, 0x70, 0x62, 0x3d, 0x6c, 0x54, 0x99, 0xd3, 0x17, 0x12, 0x5f, 0xd2, 0xd6, - 0x0d, 0xdf, 0x45, 0x8b, 0x1a, 0x74, 0x52, 0xea, 0xea, 0x68, 0x5a, 0x88, 0x1e, 0xc0, 0x65, 0xdd, - 0x71, 0x46, 0x67, 0xd3, 0xde, 0x6b, 0xcc, 0xfb, 0xad, 0x24, 0xef, 0xdb, 0xd4, 0x66, 0xda, 0x3d, - 0xd2, 0x67, 0xa4, 0xa8, 0x0b, 0x75, 0xc7, 0xc5, 0x8e, 0xee, 0x62, 0xcd, 0x71, 0x6d, 0xc7, 0xf6, - 0xf4, 0x51, 0xa3, 0xce, 0x7c, 0x3f, 0x9f, 0xe4, 0xfb, 0x90, 0xeb, 0x1f, 0x0a, 0xf5, 0x4e, 0x4a, - 0xad, 0x39, 0x71, 0x51, 0xb3, 0x08, 0xf9, 0x13, 0x7d, 0x34, 0xc1, 0xca, 0xf3, 0x50, 0x8e, 0x00, - 0x08, 0x6a, 0x40, 0x71, 0x8c, 0x3d, 0x4f, 0x1f, 0x60, 0x86, 0x37, 0x92, 0xea, 0x77, 0x95, 0x2a, - 0xac, 0x44, 0x41, 0x43, 0x19, 0x07, 0x86, 0x14, 0x0e, 0xa8, 0xe1, 0x09, 0x76, 0x3d, 0x8a, 0x01, - 0xc2, 0x50, 0x74, 0xd1, 0x33, 0x50, 0x61, 0x9b, 0x52, 0xf3, 0xc7, 0x29, 0x26, 0xe5, 0xd4, 0x15, - 0x26, 0xbc, 0x2f, 0x94, 0xd6, 0xa1, 0xec, 0x6c, 0x39, 0x81, 0x4a, 0x96, 0xa9, 0x80, 0xb3, 0xe5, - 0x08, 0x05, 0xe5, 0x07, 0x50, 0x9f, 0xc6, 0x10, 0x54, 0x87, 0xec, 0x43, 0x7c, 0x26, 0x9e, 0x47, - 0x9b, 0xe8, 0xb2, 0x98, 0x16, 0x7b, 0x86, 0xa4, 0x8a, 0x39, 0xfe, 0x29, 0x13, 0x18, 0x07, 0xe0, - 0x81, 0x6e, 0x43, 0x8e, 0x62, 0xb1, 0x80, 0x55, 0x79, 0x83, 0x03, 0xf5, 0x86, 0x0f, 0xd4, 0x1b, - 0x5d, 0x1f, 0xa8, 0x9b, 0xa5, 0x2f, 0xbf, 0x5e, 0x4f, 0x7d, 0xfe, 0xd7, 0xf5, 0xb4, 0xca, 0x2c, - 0xd0, 0x93, 0xf4, 0xac, 0xeb, 0xa6, 0xa5, 0x99, 0x86, 0x78, 0x4e, 0x91, 0xf5, 0x77, 0x0c, 0xb4, - 0x0b, 0xf5, 0xbe, 0x6d, 0x79, 0xd8, 0xf2, 0x26, 0x9e, 0xc6, 0x03, 0x81, 0x00, 0xd3, 0xd9, 0xb3, - 0xd8, 0xf2, 0x15, 0x0f, 0x99, 0x9e, 0x5a, 0xeb, 0xc7, 0x05, 0xe8, 0x2e, 0xc0, 0x89, 0x3e, 0x32, - 0x0d, 0x9d, 0xd8, 0xae, 0xd7, 0xc8, 0xdd, 0xc8, 0xce, 0x75, 0x73, 0xdf, 0x57, 0xb9, 0xe7, 0x18, - 0x3a, 0xc1, 0xcd, 0x1c, 0x7d, 0x5b, 0x35, 0x62, 0x89, 0x9e, 0x83, 0x9a, 0xee, 0x38, 0x9a, 0x47, - 0x74, 0x82, 0xb5, 0xde, 0x19, 0xc1, 0x1e, 0x83, 0xd8, 0x15, 0xb5, 0xa2, 0x3b, 0xce, 0x11, 0x95, - 0x36, 0xa9, 0x10, 0x3d, 0x0b, 0x55, 0x0a, 0xa7, 0xa6, 0x3e, 0xd2, 0x86, 0xd8, 0x1c, 0x0c, 0x09, - 0x83, 0xd2, 0xac, 0x5a, 0x11, 0xd2, 0x0e, 0x13, 0x2a, 0x46, 0xb0, 0x11, 0x18, 0x94, 0x22, 0x04, - 0x39, 0x43, 0x27, 0x3a, 0x5b, 0xc8, 0x15, 0x95, 0xb5, 0xa9, 0xcc, 0xd1, 0xc9, 0x50, 0x2c, 0x0f, - 0x6b, 0xa3, 0x2b, 0x50, 0x10, 0x6e, 0xb3, 0xcc, 0xad, 0xe8, 0xd1, 0x6f, 0xe6, 0xb8, 0xf6, 0x09, - 0x66, 0xb1, 0xa3, 0xa4, 0xf2, 0x8e, 0xf2, 0xab, 0x0c, 0xac, 0xce, 0x80, 0x2e, 0xf5, 0x3b, 0xd4, - 0xbd, 0xa1, 0xff, 0x2c, 0xda, 0x46, 0xaf, 0x53, 0xbf, 0xba, 0x81, 0x5d, 0x11, 0xec, 0x1a, 0xd1, - 0x25, 0xe2, 0x81, 0xbc, 0xc3, 0xc6, 0xc5, 0xd2, 0x08, 0x6d, 0x74, 0x00, 0xf5, 0x91, 0xee, 0x11, - 0x8d, 0x83, 0x98, 0x16, 0x09, 0x7c, 0xb3, 0xd0, 0xbd, 0xa7, 0xfb, 0xb0, 0x47, 0x37, 0xbb, 0x70, - 0x54, 0x1d, 0xc5, 0xa4, 0x48, 0x85, 0xcb, 0xbd, 0xb3, 0x47, 0xba, 0x45, 0x4c, 0x0b, 0x6b, 0x33, - 0x5f, 0xee, 0xc9, 0x19, 0xa7, 0xed, 0x13, 0xd3, 0xc0, 0x56, 0xdf, 0xff, 0x64, 0x97, 0x02, 0xe3, - 0xe0, 0x93, 0x7a, 0x8a, 0x0a, 0xd5, 0x78, 0xd8, 0x40, 0x55, 0xc8, 0x90, 0x53, 0xb1, 0x00, 0x19, - 0x72, 0x8a, 0xbe, 0x07, 0x39, 0x3a, 0x49, 0x36, 0xf9, 0xea, 0x9c, 0x98, 0x2d, 0xec, 0xba, 0x67, - 0x0e, 0x56, 0x99, 0xa6, 0xa2, 0x04, 0xa7, 0x21, 0x08, 0x25, 0xd3, 0x5e, 0x95, 0x17, 0xa0, 0x36, - 0x15, 0x2b, 0x22, 0xdf, 0x2f, 0x1d, 0xfd, 0x7e, 0x4a, 0x0d, 0x2a, 0xb1, 0xc0, 0xa0, 0x5c, 0x81, - 0xcb, 0xf3, 0x70, 0x5e, 0x19, 0x06, 0xf2, 0x18, 0x5e, 0xa3, 0xd7, 0xa0, 0x14, 0x00, 0x3d, 0x3f, - 0x8d, 0xb3, 0x6b, 0xe5, 0x2b, 0xab, 0x81, 0x2a, 0x3d, 0x86, 0x74, 0x5b, 0xb3, 0xfd, 0x90, 0x61, - 0x2f, 0x5e, 0xd4, 0x1d, 0xa7, 0xa3, 0x7b, 0x43, 0xe5, 0x23, 0x68, 0x24, 0x81, 0xf8, 0xd4, 0x34, - 0x72, 0xc1, 0x36, 0xbc, 0x02, 0x85, 0x63, 0xdb, 0x1d, 0xeb, 0x84, 0x39, 0xab, 0xa8, 0xa2, 0x47, - 0xb7, 0x27, 0x07, 0xf4, 0x2c, 0x13, 0xf3, 0x8e, 0xa2, 0xc1, 0x93, 0x89, 0x40, 0x4e, 0x4d, 0x4c, - 0xcb, 0xc0, 0x7c, 0x3d, 0x2b, 0x2a, 0xef, 0x84, 0x8e, 0xf8, 0xcb, 0xf2, 0x0e, 0x7d, 0xac, 0xc7, - 0xe6, 0xca, 0xfc, 0x4b, 0xaa, 0xe8, 0x29, 0x1a, 0x5c, 0x99, 0x8f, 0xe6, 0xe8, 0x3a, 0x00, 0xc7, - 0x53, 0x71, 0xea, 0xb2, 0x37, 0x57, 0x54, 0x89, 0x49, 0xee, 0xd0, 0xa3, 0xf7, 0x1c, 0xd4, 0xc2, - 0x61, 0xcd, 0x33, 0x1f, 0xf1, 0xad, 0x91, 0x55, 0x2b, 0x81, 0xce, 0x91, 0xf9, 0x08, 0x2b, 0xbf, - 0x97, 0xa0, 0xa4, 0x62, 0xcf, 0xa1, 0xa0, 0x83, 0x9a, 0x20, 0xe1, 0xd3, 0x3e, 0xe6, 0x1c, 0x2e, - 0x9d, 0xc8, 0x81, 0xb8, 0x76, 0xdb, 0xd7, 0xa4, 0x04, 0x24, 0x30, 0x43, 0xaf, 0x0a, 0x9e, 0x9a, - 0x4c, 0x39, 0x85, 0x79, 0x94, 0xa8, 0xbe, 0xee, 0x13, 0xd5, 0x6c, 0x22, 0xe7, 0xe0, 0x56, 0x53, - 0x4c, 0xf5, 0x55, 0xc1, 0x54, 0x73, 0x0b, 0x1e, 0x16, 0xa3, 0xaa, 0xad, 0x18, 0x55, 0xcd, 0x2f, - 0x98, 0x66, 0x02, 0x57, 0x6d, 0xc5, 0xb8, 0x6a, 0x61, 0x81, 0x93, 0x04, 0xb2, 0xfa, 0xba, 0x4f, - 0x56, 0x8b, 0x0b, 0xa6, 0x3d, 0xc5, 0x56, 0xef, 0xc6, 0xd9, 0x2a, 0x67, 0x9a, 0xcf, 0x24, 0x5a, - 0x27, 0xd2, 0xd5, 0x1f, 0x46, 0xe8, 0xaa, 0x94, 0xc8, 0x15, 0xb9, 0x93, 0x39, 0x7c, 0xb5, 0x15, - 0xe3, 0xab, 0xb0, 0x60, 0x0d, 0x12, 0x08, 0xeb, 0x3b, 0x51, 0xc2, 0x5a, 0x4e, 0xe4, 0xbc, 0x62, - 0xd3, 0xcc, 0x63, 0xac, 0x6f, 0x04, 0x8c, 0x75, 0x25, 0x91, 0x72, 0x8b, 0x39, 0x4c, 0x53, 0xd6, - 0x83, 0x19, 0xca, 0xca, 0x29, 0xe6, 0x73, 0x89, 0x2e, 0x16, 0x70, 0xd6, 0x83, 0x19, 0xce, 0x5a, - 0x5d, 0xe0, 0x70, 0x01, 0x69, 0xfd, 0xc5, 0x7c, 0xd2, 0x9a, 0x4c, 0x2b, 0xc5, 0x6b, 0x2e, 0xc7, - 0x5a, 0xb5, 0x04, 0xd6, 0xca, 0x99, 0xe5, 0x8b, 0x89, 0xee, 0x97, 0xa6, 0xad, 0xf7, 0xe6, 0xd0, - 0xd6, 0x55, 0xe6, 0xfc, 0x66, 0xa2, 0xf3, 0x8b, 0xf0, 0xd6, 0x17, 0x28, 0x3d, 0x98, 0xc2, 0x23, - 0x0a, 0xb1, 0xd8, 0x75, 0x6d, 0x57, 0x50, 0x42, 0xde, 0x51, 0x6e, 0x52, 0xc2, 0x12, 0x62, 0xcf, - 0x39, 0x1c, 0x97, 0x85, 0xb2, 0x08, 0xde, 0x28, 0xbf, 0x4b, 0x87, 0xb6, 0x2c, 0xc6, 0x47, 0xc9, - 0x8e, 0x24, 0xc8, 0x4e, 0x84, 0xfa, 0x66, 0xe2, 0xd4, 0x77, 0x1d, 0xca, 0x34, 0x44, 0x4d, 0xb1, - 0x5a, 0xdd, 0xf1, 0x59, 0x2d, 0xba, 0x05, 0xab, 0x8c, 0x83, 0x70, 0xc4, 0x16, 0x71, 0x29, 0xc7, - 0xe0, 0xba, 0x46, 0x07, 0xf8, 0x9e, 0xe7, 0x01, 0xea, 0x65, 0xb8, 0x14, 0xd1, 0x0d, 0x42, 0x1f, - 0xa7, 0x72, 0xf5, 0x40, 0x7b, 0x5b, 0xc4, 0xc0, 0xf7, 0xc3, 0x05, 0x0a, 0x19, 0x33, 0x82, 0x5c, - 0xdf, 0x36, 0xb0, 0x08, 0x4c, 0xac, 0x4d, 0x59, 0xf4, 0xc8, 0x1e, 0x88, 0xf0, 0x43, 0x9b, 0x54, - 0x2b, 0x00, 0x57, 0x89, 0x63, 0xa7, 0xf2, 0xc7, 0x74, 0xe8, 0x2f, 0x24, 0xd1, 0xf3, 0xf8, 0x6e, - 0xfa, 0x7f, 0xc3, 0x77, 0x33, 0xdf, 0x9a, 0xef, 0x46, 0x89, 0x41, 0x36, 0x4e, 0x0c, 0xfe, 0x95, - 0x0e, 0xbf, 0x70, 0xc0, 0x5e, 0xbf, 0xdd, 0x8a, 0x84, 0x51, 0x3e, 0xcf, 0xbe, 0x97, 0x88, 0xf2, - 0x22, 0x27, 0x29, 0xb0, 0xe7, 0xc6, 0x73, 0x92, 0x22, 0x8f, 0xfb, 0xac, 0x83, 0x6e, 0x83, 0xc4, - 0x4a, 0x50, 0x9a, 0xed, 0x78, 0x02, 0xc7, 0x9f, 0x8a, 0xce, 0x95, 0x57, 0x9a, 0x36, 0x0e, 0xa9, - 0xce, 0x81, 0xe3, 0xa9, 0x25, 0x47, 0xb4, 0x22, 0x04, 0x46, 0x8a, 0xf1, 0xe8, 0x6b, 0x20, 0xd1, - 0xb7, 0xf7, 0x1c, 0xbd, 0x8f, 0x19, 0x26, 0x4b, 0x6a, 0x28, 0x50, 0x1e, 0x00, 0x9a, 0x8d, 0x0a, - 0xa8, 0x03, 0x05, 0x7c, 0x82, 0x2d, 0xe2, 0x31, 0x1e, 0x51, 0xde, 0xba, 0x32, 0x87, 0xa4, 0x62, - 0x8b, 0x34, 0x1b, 0x74, 0x91, 0xff, 0xf9, 0xf5, 0x7a, 0x9d, 0x6b, 0xbf, 0x64, 0x8f, 0x4d, 0x82, - 0xc7, 0x0e, 0x39, 0x53, 0x85, 0xbd, 0xf2, 0x97, 0x0c, 0x65, 0x8c, 0xb1, 0x88, 0x31, 0x77, 0x6d, - 0xfd, 0x03, 0x94, 0x89, 0x64, 0x0b, 0xcb, 0xad, 0xf7, 0x1a, 0xc0, 0x40, 0xf7, 0xb4, 0x4f, 0x75, - 0x8b, 0x60, 0x43, 0x2c, 0x7a, 0x44, 0x82, 0x64, 0x28, 0xd1, 0xde, 0xc4, 0xc3, 0x86, 0x48, 0x5c, - 0x82, 0x7e, 0x64, 0x9e, 0xc5, 0xef, 0x36, 0xcf, 0xf8, 0x2a, 0x97, 0xa6, 0x56, 0x39, 0xc2, 0xe6, - 0xa4, 0x28, 0x9b, 0xa3, 0xef, 0xe6, 0xb8, 0xa6, 0xed, 0x9a, 0xe4, 0x8c, 0x7d, 0x9a, 0xac, 0x1a, - 0xf4, 0x69, 0x7e, 0x3c, 0xc6, 0x63, 0xc7, 0xb6, 0x47, 0x1a, 0x07, 0xaf, 0x32, 0x33, 0x5d, 0x11, - 0xc2, 0x36, 0xc3, 0xb0, 0x5f, 0x67, 0xc2, 0xe3, 0x17, 0xb2, 0xf6, 0xff, 0xbb, 0x05, 0x56, 0x7e, - 0xc3, 0x52, 0xf9, 0x38, 0x27, 0x40, 0x47, 0xb0, 0x1a, 0x1c, 0x7f, 0x6d, 0xc2, 0x60, 0xc1, 0xdf, - 0xd0, 0xcb, 0xe2, 0x47, 0xfd, 0x24, 0x2e, 0xf6, 0xd0, 0x4f, 0xe0, 0xea, 0x14, 0xb4, 0x05, 0xae, - 0x33, 0x4b, 0x22, 0xdc, 0x13, 0x71, 0x84, 0xf3, 0x3d, 0x87, 0x6b, 0x95, 0xfd, 0x8e, 0x87, 0x6e, - 0x87, 0x66, 0x87, 0x51, 0x86, 0x33, 0xf7, 0xeb, 0x3f, 0x03, 0x15, 0x17, 0x13, 0xdd, 0xb4, 0xb4, - 0x58, 0xfe, 0xbd, 0xc2, 0x85, 0x22, 0xab, 0x3f, 0x84, 0x27, 0xe6, 0x32, 0x1d, 0xf4, 0x7d, 0x90, - 0x42, 0x92, 0x94, 0x4e, 0x48, 0x65, 0x83, 0xf4, 0x2c, 0xd4, 0x55, 0xfe, 0x90, 0x0e, 0x5d, 0xc6, - 0x13, 0xbe, 0x36, 0x14, 0x5c, 0xec, 0x4d, 0x46, 0x3c, 0x05, 0xab, 0x6e, 0xbd, 0xbc, 0x1c, 0x47, - 0xa2, 0xd2, 0xc9, 0x88, 0xa8, 0xc2, 0x58, 0x79, 0x00, 0x05, 0x2e, 0x41, 0x65, 0x28, 0xde, 0xdb, - 0xdf, 0xdd, 0x3f, 0xf8, 0x60, 0xbf, 0x9e, 0x42, 0x00, 0x85, 0xed, 0x56, 0xab, 0x7d, 0xd8, 0xad, - 0xa7, 0x91, 0x04, 0xf9, 0xed, 0xe6, 0x81, 0xda, 0xad, 0x67, 0xa8, 0x58, 0x6d, 0xbf, 0xd7, 0x6e, - 0x75, 0xeb, 0x59, 0xb4, 0x0a, 0x15, 0xde, 0xd6, 0xee, 0x1e, 0xa8, 0xef, 0x6f, 0x77, 0xeb, 0xb9, - 0x88, 0xe8, 0xa8, 0xbd, 0x7f, 0xa7, 0xad, 0xd6, 0xf3, 0xca, 0x2b, 0x34, 0xc7, 0x4b, 0x60, 0x55, - 0x61, 0x36, 0x97, 0x8e, 0x64, 0x73, 0xca, 0x6f, 0x33, 0x20, 0x27, 0x53, 0x25, 0xf4, 0xde, 0xd4, - 0xc4, 0xb7, 0x2e, 0xc0, 0xb3, 0xa6, 0x66, 0x8f, 0x9e, 0x85, 0xaa, 0x8b, 0x8f, 0x31, 0xe9, 0x0f, - 0x39, 0x75, 0xe3, 0x11, 0xb3, 0xa2, 0x56, 0x84, 0x94, 0x19, 0x79, 0x5c, 0xed, 0x63, 0xdc, 0x27, - 0x1a, 0x87, 0x22, 0xbe, 0xe9, 0x24, 0xaa, 0x46, 0xa5, 0x47, 0x5c, 0xa8, 0x7c, 0x74, 0xa1, 0xb5, - 0x94, 0x20, 0xaf, 0xb6, 0xbb, 0xea, 0x4f, 0xeb, 0x59, 0x84, 0xa0, 0xca, 0x9a, 0xda, 0xd1, 0xfe, - 0xf6, 0xe1, 0x51, 0xe7, 0x80, 0xae, 0xe5, 0x25, 0xa8, 0xf9, 0x6b, 0xe9, 0x0b, 0xf3, 0xca, 0x6d, - 0xb8, 0x9a, 0xc0, 0xf3, 0x16, 0x64, 0xb4, 0xca, 0x7f, 0xd2, 0x50, 0x9b, 0x3a, 0x5a, 0x68, 0x0b, - 0xf2, 0x3c, 0x71, 0x48, 0xba, 0x15, 0x61, 0xc8, 0x20, 0xce, 0x21, 0x57, 0x45, 0x6f, 0x41, 0x09, - 0x8b, 0x92, 0xcb, 0xbc, 0x23, 0xcc, 0x4b, 0x45, 0x7e, 0x51, 0x46, 0x98, 0x06, 0x16, 0xe8, 0x6d, - 0x90, 0x02, 0x8c, 0x10, 0xd9, 0xea, 0xd3, 0xb3, 0xe6, 0x01, 0xba, 0x08, 0xfb, 0xd0, 0x06, 0xbd, - 0x11, 0xd2, 0xc4, 0xdc, 0x6c, 0xba, 0x22, 0xcc, 0xb9, 0x82, 0x30, 0xf6, 0xf5, 0x95, 0x16, 0x94, - 0x23, 0xf3, 0x41, 0x4f, 0x81, 0x34, 0xd6, 0x4f, 0x45, 0x29, 0x8f, 0x17, 0x63, 0x4a, 0x63, 0xfd, - 0x94, 0x57, 0xf1, 0xae, 0x42, 0x91, 0x0e, 0x0e, 0x74, 0x4f, 0xe4, 0xfd, 0x85, 0xb1, 0x7e, 0xfa, - 0xae, 0xee, 0x29, 0x1f, 0x42, 0x35, 0x5e, 0xc6, 0xa2, 0x7b, 0xd8, 0xb5, 0x27, 0x96, 0xc1, 0x7c, - 0xe4, 0x55, 0xde, 0x41, 0xaf, 0x41, 0xfe, 0xc4, 0xe6, 0x30, 0x37, 0xff, 0xb0, 0xdf, 0xb7, 0x09, - 0x8e, 0x94, 0xc1, 0xb8, 0xb6, 0xf2, 0x08, 0xf2, 0x0c, 0xb6, 0x28, 0x04, 0xb1, 0x82, 0x94, 0xa0, - 0xc8, 0xb4, 0x8d, 0x3e, 0x04, 0xd0, 0x09, 0x71, 0xcd, 0xde, 0x24, 0x74, 0xbc, 0x3e, 0x1f, 0xf6, - 0xb6, 0x7d, 0xbd, 0xe6, 0x35, 0x81, 0x7f, 0x97, 0x43, 0xd3, 0x08, 0x06, 0x46, 0x1c, 0x2a, 0xfb, - 0x50, 0x8d, 0xdb, 0x46, 0x4b, 0xc3, 0x2b, 0x73, 0x4a, 0xc3, 0x01, 0x0d, 0x0b, 0x48, 0x5c, 0x96, - 0x17, 0x1f, 0x59, 0x47, 0xf9, 0x2c, 0x0d, 0xa5, 0xee, 0xa9, 0x38, 0x10, 0x09, 0x75, 0xaf, 0xd0, - 0x34, 0x13, 0xad, 0xf2, 0xf0, 0x42, 0x5a, 0x36, 0x28, 0xcf, 0xbd, 0x13, 0x1c, 0xf9, 0xdc, 0xb2, - 0x69, 0xb2, 0x5f, 0xa7, 0x14, 0x30, 0xf7, 0x26, 0x48, 0xc1, 0xae, 0xa2, 0xb9, 0x86, 0x6e, 0x18, - 0x2e, 0xf6, 0x3c, 0x31, 0x37, 0xbf, 0xcb, 0xca, 0xa8, 0xf6, 0xa7, 0xa2, 0x8e, 0x94, 0x55, 0x79, - 0x47, 0x31, 0xa0, 0x36, 0x15, 0xf0, 0xd0, 0x9b, 0x50, 0x74, 0x26, 0x3d, 0xcd, 0x5f, 0x9e, 0xa9, - 0xc3, 0xe3, 0xf3, 0xce, 0x49, 0x6f, 0x64, 0xf6, 0x77, 0xf1, 0x99, 0xff, 0x32, 0xce, 0xa4, 0xb7, - 0xcb, 0x57, 0x91, 0x3f, 0x25, 0x13, 0x7d, 0xca, 0x09, 0x94, 0xfc, 0x4d, 0x81, 0x7e, 0x14, 0x3d, - 0x27, 0x7e, 0x71, 0x3d, 0x31, 0x08, 0x0b, 0xf7, 0x91, 0x63, 0x72, 0x0b, 0x56, 0x3d, 0x73, 0x60, - 0x61, 0x43, 0x0b, 0xb3, 0x1d, 0xf6, 0xb4, 0x92, 0x5a, 0xe3, 0x03, 0x7b, 0x7e, 0xaa, 0xa3, 0xfc, - 0x3b, 0x0d, 0x25, 0xff, 0xc0, 0xa2, 0x57, 0x22, 0xfb, 0xae, 0x3a, 0xa7, 0x24, 0xe4, 0x2b, 0x86, - 0x95, 0xd0, 0xf8, 0xbb, 0x66, 0x2e, 0xfe, 0xae, 0x49, 0x25, 0x6d, 0xff, 0x6e, 0x21, 0x77, 0xe1, - 0xbb, 0x85, 0x97, 0x00, 0x11, 0x9b, 0xe8, 0x23, 0xed, 0xc4, 0x26, 0xa6, 0x35, 0xd0, 0xf8, 0x62, - 0x73, 0x2e, 0x56, 0x67, 0x23, 0xf7, 0xd9, 0xc0, 0x21, 0x5b, 0xf7, 0x5f, 0xa6, 0xa1, 0x14, 0x44, - 0xd5, 0x8b, 0x16, 0x36, 0xaf, 0x40, 0x41, 0x04, 0x0e, 0x5e, 0xd9, 0x14, 0xbd, 0xa0, 0xc6, 0x9e, - 0x8b, 0xd4, 0xd8, 0x65, 0x28, 0x8d, 0x31, 0xd1, 0x19, 0x3e, 0xf3, 0x84, 0x33, 0xe8, 0xdf, 0x7a, - 0x03, 0xca, 0x91, 0x1a, 0x33, 0x3d, 0x79, 0xfb, 0xed, 0x0f, 0xea, 0x29, 0xb9, 0xf8, 0xd9, 0x17, - 0x37, 0xb2, 0xfb, 0xf8, 0x53, 0xba, 0x67, 0xd5, 0x76, 0xab, 0xd3, 0x6e, 0xed, 0xd6, 0xd3, 0x72, - 0xf9, 0xb3, 0x2f, 0x6e, 0x14, 0x55, 0xcc, 0x2a, 0x49, 0xb7, 0x3a, 0xb0, 0x12, 0xfd, 0x2a, 0xf1, - 0xd8, 0x83, 0xa0, 0x7a, 0xe7, 0xde, 0xe1, 0xde, 0x4e, 0x6b, 0xbb, 0xdb, 0xd6, 0xee, 0x1f, 0x74, - 0xdb, 0xf5, 0x34, 0xba, 0x0a, 0x97, 0xf6, 0x76, 0xde, 0xed, 0x74, 0xb5, 0xd6, 0xde, 0x4e, 0x7b, - 0xbf, 0xab, 0x6d, 0x77, 0xbb, 0xdb, 0xad, 0xdd, 0x7a, 0x66, 0xeb, 0x1f, 0x00, 0xb5, 0xed, 0x66, - 0x6b, 0x87, 0xc6, 0x4d, 0xb3, 0xaf, 0x8b, 0x4a, 0x5d, 0x8e, 0xe5, 0xfb, 0xe7, 0x5e, 0x99, 0xcb, - 0xe7, 0x17, 0x2a, 0xd1, 0x5d, 0xc8, 0xb3, 0x52, 0x00, 0x3a, 0xff, 0x0e, 0x5d, 0x5e, 0x50, 0xb9, - 0xa4, 0x2f, 0xc3, 0x8e, 0xc7, 0xb9, 0x97, 0xea, 0xf2, 0xf9, 0x85, 0x4c, 0xa4, 0x82, 0x14, 0xe6, - 0xf2, 0x8b, 0x2f, 0xd9, 0xe5, 0x25, 0x8a, 0x9b, 0xd4, 0x67, 0x98, 0x50, 0x2c, 0xbe, 0x74, 0x96, - 0x97, 0x00, 0x30, 0xb4, 0x07, 0x45, 0x3f, 0x07, 0x5c, 0x74, 0x0d, 0x2e, 0x2f, 0x2c, 0x3c, 0xd2, - 0x4f, 0xc0, 0x73, 0xf5, 0xf3, 0xef, 0xf4, 0xe5, 0x05, 0x55, 0x54, 0xb4, 0x03, 0x05, 0xc1, 0x92, - 0x17, 0x5c, 0x6d, 0xcb, 0x8b, 0x0a, 0x89, 0x74, 0xd1, 0xc2, 0x22, 0xc8, 0xe2, 0x3f, 0x15, 0xe4, - 0x25, 0x0a, 0xc4, 0xe8, 0x1e, 0x40, 0x24, 0x33, 0x5f, 0xe2, 0x17, 0x04, 0x79, 0x99, 0xc2, 0x2f, - 0x3a, 0x80, 0x52, 0x90, 0x28, 0x2d, 0xfc, 0x21, 0x40, 0x5e, 0x5c, 0x81, 0x45, 0x0f, 0xa0, 0x12, - 0xcf, 0x10, 0x96, 0xbb, 0xe6, 0x97, 0x97, 0x2c, 0xad, 0x52, 0xff, 0xf1, 0x74, 0x61, 0xb9, 0x6b, - 0x7f, 0x79, 0xc9, 0x4a, 0x2b, 0xfa, 0x18, 0x56, 0x67, 0xe9, 0xfc, 0xf2, 0x7f, 0x01, 0xc8, 0x17, - 0xa8, 0xbd, 0xa2, 0x31, 0xa0, 0x39, 0x69, 0xc0, 0x05, 0x7e, 0x0a, 0x90, 0x2f, 0x52, 0x8a, 0x45, - 0x06, 0xd4, 0xa6, 0xb9, 0xf5, 0xb2, 0x3f, 0x09, 0xc8, 0x4b, 0x97, 0x65, 0x9b, 0xed, 0x2f, 0xbf, - 0x59, 0x4b, 0x7f, 0xf5, 0xcd, 0x5a, 0xfa, 0x6f, 0xdf, 0xac, 0xa5, 0x3f, 0x7f, 0xbc, 0x96, 0xfa, - 0xea, 0xf1, 0x5a, 0xea, 0xcf, 0x8f, 0xd7, 0x52, 0x3f, 0x7b, 0x71, 0x60, 0x92, 0xe1, 0xa4, 0xb7, - 0xd1, 0xb7, 0xc7, 0x9b, 0xd1, 0xff, 0xa2, 0xe6, 0xfd, 0xab, 0xd5, 0x2b, 0xb0, 0x70, 0xf8, 0xea, - 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x5c, 0x29, 0x35, 0x72, 0xcb, 0x25, 0x00, 0x00, + // 2917 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x4b, 0x93, 0x23, 0xc5, + 0xb5, 0xd6, 0x5b, 0xaa, 0xd3, 0xad, 0x47, 0xe7, 0x0c, 0x33, 0x42, 0xcc, 0x74, 0x0f, 0x45, 0x00, + 0xc3, 0x00, 0xdd, 0x97, 0x26, 0xe0, 0x0e, 0x17, 0xee, 0x85, 0x96, 0x46, 0x83, 0x9a, 0x69, 0xba, + 0xfb, 0x66, 0x6b, 0x06, 0xbf, 0x98, 0xa2, 0xa4, 0xca, 0x96, 0x8a, 0x91, 0xaa, 0x8a, 0xaa, 0x54, + 0xd3, 0x3d, 0x4b, 0x87, 0xbd, 0xc1, 0xe1, 0x08, 0x96, 0xde, 0xf0, 0x3f, 0xbc, 0x70, 0x78, 0xe3, + 0x0d, 0x11, 0xde, 0xb0, 0xf4, 0xc2, 0x81, 0x1d, 0xb0, 0x70, 0xd8, 0x7f, 0xc0, 0x2b, 0x87, 0x1d, + 0xf9, 0xa8, 0x97, 0xa4, 0x6a, 0xa9, 0xc1, 0x3b, 0xef, 0x32, 0x4f, 0x9e, 0x73, 0xb2, 0x32, 0x2b, + 0xf3, 0x3b, 0xdf, 0x39, 0x55, 0xf0, 0x14, 0x25, 0x96, 0x41, 0xdc, 0xb1, 0x69, 0xd1, 0x2d, 0xbd, + 0xd7, 0x37, 0xb7, 0xe8, 0x99, 0x43, 0xbc, 0x4d, 0xc7, 0xb5, 0xa9, 0x8d, 0xaa, 0xe1, 0xe0, 0x26, + 0x1b, 0x6c, 0x5c, 0x8f, 0x68, 0xf7, 0xdd, 0x33, 0x87, 0xda, 0x5b, 0x8e, 0x6b, 0xdb, 0xc7, 0x42, + 0xbf, 0x71, 0x2d, 0x32, 0xcc, 0xfd, 0x44, 0xbd, 0xc5, 0x46, 0xa5, 0xf1, 0x23, 0x72, 0xe6, 0x8f, + 0x5e, 0x9f, 0xb1, 0x75, 0x74, 0x57, 0x1f, 0xfb, 0xc3, 0x1b, 0x03, 0xdb, 0x1e, 0x8c, 0xc8, 0x16, + 0xef, 0xf5, 0x26, 0xc7, 0x5b, 0xd4, 0x1c, 0x13, 0x8f, 0xea, 0x63, 0x47, 0x2a, 0x5c, 0x1e, 0xd8, + 0x03, 0x9b, 0x37, 0xb7, 0x58, 0x4b, 0x48, 0xd5, 0xbf, 0x94, 0xa0, 0x88, 0xc9, 0x27, 0x13, 0xe2, + 0x51, 0xb4, 0x0d, 0x39, 0xd2, 0x1f, 0xda, 0xf5, 0xf4, 0x8d, 0xf4, 0xcd, 0x95, 0xed, 0x6b, 0x9b, + 0x53, 0x8b, 0xdb, 0x94, 0x7a, 0xed, 0xfe, 0xd0, 0xee, 0xa4, 0x30, 0xd7, 0x45, 0xaf, 0x41, 0xfe, + 0x78, 0x34, 0xf1, 0x86, 0xf5, 0x0c, 0x37, 0xba, 0x9e, 0x64, 0x74, 0x97, 0x29, 0x75, 0x52, 0x58, + 0x68, 0xb3, 0xa9, 0x4c, 0xeb, 0xd8, 0xae, 0x67, 0xcf, 0x9f, 0x6a, 0xd7, 0x3a, 0xe6, 0x53, 0x31, + 0x5d, 0xd4, 0x04, 0xf0, 0x08, 0xd5, 0x6c, 0x87, 0x9a, 0xb6, 0x55, 0xcf, 0x71, 0xcb, 0xa7, 0x93, + 0x2c, 0x8f, 0x08, 0x3d, 0xe0, 0x8a, 0x9d, 0x14, 0x56, 0x3c, 0xbf, 0xc3, 0x7c, 0x98, 0x96, 0x49, + 0xb5, 0xfe, 0x50, 0x37, 0xad, 0x7a, 0xfe, 0x7c, 0x1f, 0xbb, 0x96, 0x49, 0x5b, 0x4c, 0x91, 0xf9, + 0x30, 0xfd, 0x0e, 0x5b, 0xf2, 0x27, 0x13, 0xe2, 0x9e, 0xd5, 0x0b, 0xe7, 0x2f, 0xf9, 0xff, 0x99, + 0x12, 0x5b, 0x32, 0xd7, 0x46, 0x6d, 0x58, 0xe9, 0x91, 0x81, 0x69, 0x69, 0xbd, 0x91, 0xdd, 0x7f, + 0x54, 0x2f, 0x72, 0x63, 0x35, 0xc9, 0xb8, 0xc9, 0x54, 0x9b, 0x4c, 0xb3, 0x93, 0xc2, 0xd0, 0x0b, + 0x7a, 0xe8, 0x2d, 0x28, 0xf5, 0x87, 0xa4, 0xff, 0x48, 0xa3, 0xa7, 0xf5, 0x12, 0xf7, 0xb1, 0x91, + 0xe4, 0xa3, 0xc5, 0xf4, 0xba, 0xa7, 0x9d, 0x14, 0x2e, 0xf6, 0x45, 0x93, 0xad, 0xdf, 0x20, 0x23, + 0xf3, 0x84, 0xb8, 0xcc, 0x5e, 0x39, 0x7f, 0xfd, 0x77, 0x84, 0x26, 0xf7, 0xa0, 0x18, 0x7e, 0x07, + 0xbd, 0x0d, 0x0a, 0xb1, 0x0c, 0xb9, 0x0c, 0xe0, 0x2e, 0x6e, 0x24, 0x9e, 0x15, 0xcb, 0xf0, 0x17, + 0x51, 0x22, 0xb2, 0x8d, 0x6e, 0x43, 0xa1, 0x6f, 0x8f, 0xc7, 0x26, 0xad, 0xaf, 0x70, 0xeb, 0xf5, + 0xc4, 0x05, 0x70, 0xad, 0x4e, 0x0a, 0x4b, 0x7d, 0xb4, 0x0f, 0x95, 0x91, 0xe9, 0x51, 0xcd, 0xb3, + 0x74, 0xc7, 0x1b, 0xda, 0xd4, 0xab, 0xaf, 0x72, 0x0f, 0xcf, 0x26, 0x79, 0xd8, 0x33, 0x3d, 0x7a, + 0xe4, 0x2b, 0x77, 0x52, 0xb8, 0x3c, 0x8a, 0x0a, 0x98, 0x3f, 0xfb, 0xf8, 0x98, 0xb8, 0x81, 0xc3, + 0x7a, 0xf9, 0x7c, 0x7f, 0x07, 0x4c, 0xdb, 0xb7, 0x67, 0xfe, 0xec, 0xa8, 0x00, 0xfd, 0x18, 0x2e, + 0x8d, 0x6c, 0xdd, 0x08, 0xdc, 0x69, 0xfd, 0xe1, 0xc4, 0x7a, 0x54, 0xaf, 0x70, 0xa7, 0x2f, 0x24, + 0x3e, 0xa4, 0xad, 0x1b, 0xbe, 0x8b, 0x16, 0x33, 0xe8, 0xa4, 0xf0, 0xda, 0x68, 0x5a, 0x88, 0x1e, + 0xc2, 0x65, 0xdd, 0x71, 0x46, 0x67, 0xd3, 0xde, 0xab, 0xdc, 0xfb, 0xad, 0x24, 0xef, 0x3b, 0xcc, + 0x66, 0xda, 0x3d, 0xd2, 0x67, 0xa4, 0xa8, 0x0b, 0x35, 0xc7, 0x25, 0x8e, 0xee, 0x12, 0xcd, 0x71, + 0x6d, 0xc7, 0xf6, 0xf4, 0x51, 0xbd, 0xc6, 0x7d, 0x3f, 0x9f, 0xe4, 0xfb, 0x50, 0xe8, 0x1f, 0x4a, + 0xf5, 0x4e, 0x0a, 0x57, 0x9d, 0xb8, 0xa8, 0x59, 0x84, 0xfc, 0x89, 0x3e, 0x9a, 0x10, 0xf5, 0x79, + 0x58, 0x89, 0x00, 0x08, 0xaa, 0x43, 0x71, 0x4c, 0x3c, 0x4f, 0x1f, 0x10, 0x8e, 0x37, 0x0a, 0xf6, + 0xbb, 0x6a, 0x05, 0x56, 0xa3, 0xa0, 0xa1, 0x8e, 0x03, 0x43, 0x06, 0x07, 0xcc, 0xf0, 0x84, 0xb8, + 0x1e, 0xc3, 0x00, 0x69, 0x28, 0xbb, 0xe8, 0x19, 0x28, 0xf3, 0x43, 0xa9, 0xf9, 0xe3, 0x0c, 0x93, + 0x72, 0x78, 0x95, 0x0b, 0x1f, 0x48, 0xa5, 0x0d, 0x58, 0x71, 0xb6, 0x9d, 0x40, 0x25, 0xcb, 0x55, + 0xc0, 0xd9, 0x76, 0xa4, 0x82, 0xfa, 0x3f, 0x50, 0x9b, 0xc6, 0x10, 0x54, 0x83, 0xec, 0x23, 0x72, + 0x26, 0xe7, 0x63, 0x4d, 0x74, 0x59, 0x2e, 0x8b, 0xcf, 0xa1, 0x60, 0xb9, 0xc6, 0xdf, 0x67, 0x02, + 0xe3, 0x00, 0x3c, 0xd0, 0x6d, 0xc8, 0x31, 0x2c, 0x96, 0xb0, 0xda, 0xd8, 0x14, 0x40, 0xbd, 0xe9, + 0x03, 0xf5, 0x66, 0xd7, 0x07, 0xea, 0x66, 0xe9, 0xcb, 0xaf, 0x37, 0x52, 0x9f, 0xff, 0x69, 0x23, + 0x8d, 0xb9, 0x05, 0x7a, 0x92, 0xdd, 0x75, 0xdd, 0xb4, 0x34, 0xd3, 0x90, 0xf3, 0x14, 0x79, 0x7f, + 0xd7, 0x40, 0xf7, 0xa0, 0xd6, 0xb7, 0x2d, 0x8f, 0x58, 0xde, 0xc4, 0xd3, 0x44, 0x20, 0x90, 0x60, + 0x3a, 0x7b, 0x17, 0x5b, 0xbe, 0xe2, 0x21, 0xd7, 0xc3, 0xd5, 0x7e, 0x5c, 0x80, 0xee, 0x02, 0x9c, + 0xe8, 0x23, 0xd3, 0xd0, 0xa9, 0xed, 0x7a, 0xf5, 0xdc, 0x8d, 0xec, 0x5c, 0x37, 0x0f, 0x7c, 0x95, + 0xfb, 0x8e, 0xa1, 0x53, 0xd2, 0xcc, 0xb1, 0xa7, 0xc5, 0x11, 0x4b, 0xf4, 0x1c, 0x54, 0x75, 0xc7, + 0xd1, 0x3c, 0xaa, 0x53, 0xa2, 0xf5, 0xce, 0x28, 0xf1, 0x38, 0xc4, 0xae, 0xe2, 0xb2, 0xee, 0x38, + 0x47, 0x4c, 0xda, 0x64, 0x42, 0xf4, 0x2c, 0x54, 0x18, 0x9c, 0x9a, 0xfa, 0x48, 0x1b, 0x12, 0x73, + 0x30, 0xa4, 0x1c, 0x4a, 0xb3, 0xb8, 0x2c, 0xa5, 0x1d, 0x2e, 0x54, 0x8d, 0xe0, 0x20, 0x70, 0x28, + 0x45, 0x08, 0x72, 0x86, 0x4e, 0x75, 0xbe, 0x91, 0xab, 0x98, 0xb7, 0x99, 0xcc, 0xd1, 0xe9, 0x50, + 0x6e, 0x0f, 0x6f, 0xa3, 0x2b, 0x50, 0x90, 0x6e, 0xb3, 0xdc, 0xad, 0xec, 0xb1, 0x77, 0xe6, 0xb8, + 0xf6, 0x09, 0xe1, 0xb1, 0xa3, 0x84, 0x45, 0x47, 0xfd, 0x59, 0x06, 0xd6, 0x66, 0x40, 0x97, 0xf9, + 0x1d, 0xea, 0xde, 0xd0, 0x9f, 0x8b, 0xb5, 0xd1, 0xeb, 0xcc, 0xaf, 0x6e, 0x10, 0x57, 0x06, 0xbb, + 0x7a, 0x74, 0x8b, 0x44, 0x20, 0xef, 0xf0, 0x71, 0xb9, 0x35, 0x52, 0x1b, 0x1d, 0x40, 0x6d, 0xa4, + 0x7b, 0x54, 0x13, 0x20, 0xa6, 0x45, 0x02, 0xdf, 0x2c, 0x74, 0xef, 0xe9, 0x3e, 0xec, 0xb1, 0xc3, + 0x2e, 0x1d, 0x55, 0x46, 0x31, 0x29, 0xc2, 0x70, 0xb9, 0x77, 0xf6, 0x58, 0xb7, 0xa8, 0x69, 0x11, + 0x6d, 0xe6, 0xcd, 0x3d, 0x39, 0xe3, 0xb4, 0x7d, 0x62, 0x1a, 0xc4, 0xea, 0xfb, 0xaf, 0xec, 0x52, + 0x60, 0x1c, 0xbc, 0x52, 0x4f, 0xc5, 0x50, 0x89, 0x87, 0x0d, 0x54, 0x81, 0x0c, 0x3d, 0x95, 0x1b, + 0x90, 0xa1, 0xa7, 0xe8, 0xbf, 0x20, 0xc7, 0x16, 0xc9, 0x17, 0x5f, 0x99, 0x13, 0xb3, 0xa5, 0x5d, + 0xf7, 0xcc, 0x21, 0x98, 0x6b, 0xaa, 0x6a, 0x70, 0x1b, 0x82, 0x50, 0x32, 0xed, 0x55, 0x7d, 0x01, + 0xaa, 0x53, 0xb1, 0x22, 0xf2, 0xfe, 0xd2, 0xd1, 0xf7, 0xa7, 0x56, 0xa1, 0x1c, 0x0b, 0x0c, 0xea, + 0x15, 0xb8, 0x3c, 0x0f, 0xe7, 0xd5, 0x61, 0x20, 0x8f, 0xe1, 0x35, 0x7a, 0x0d, 0x4a, 0x01, 0xd0, + 0x8b, 0xdb, 0x38, 0xbb, 0x57, 0xbe, 0x32, 0x0e, 0x54, 0xd9, 0x35, 0x64, 0xc7, 0x9a, 0x9f, 0x87, + 0x0c, 0x7f, 0xf0, 0xa2, 0xee, 0x38, 0x1d, 0xdd, 0x1b, 0xaa, 0x1f, 0x41, 0x3d, 0x09, 0xc4, 0xa7, + 0x96, 0x91, 0x0b, 0x8e, 0xe1, 0x15, 0x28, 0x1c, 0xdb, 0xee, 0x58, 0xa7, 0xdc, 0x59, 0x19, 0xcb, + 0x1e, 0x3b, 0x9e, 0x02, 0xd0, 0xb3, 0x5c, 0x2c, 0x3a, 0xaa, 0x06, 0x4f, 0x26, 0x02, 0x39, 0x33, + 0x31, 0x2d, 0x83, 0x88, 0xfd, 0x2c, 0x63, 0xd1, 0x09, 0x1d, 0x89, 0x87, 0x15, 0x1d, 0x36, 0xad, + 0xc7, 0xd7, 0xca, 0xfd, 0x2b, 0x58, 0xf6, 0xd4, 0x5f, 0xa6, 0xe1, 0xca, 0x7c, 0x38, 0x47, 0xd7, + 0x01, 0x04, 0xa0, 0xca, 0x6b, 0x97, 0xbd, 0xb9, 0x8a, 0x15, 0x2e, 0xb9, 0xc3, 0xee, 0xde, 0x73, + 0x50, 0x0d, 0x87, 0x35, 0xcf, 0x7c, 0x2c, 0xce, 0x46, 0x16, 0x97, 0x03, 0x9d, 0x23, 0xf3, 0x31, + 0x41, 0x2f, 0x41, 0xfe, 0xc4, 0x66, 0x60, 0x90, 0xe5, 0xe7, 0xf3, 0xca, 0xec, 0xb5, 0x79, 0x60, + 0x53, 0x82, 0x85, 0x92, 0xfa, 0x1b, 0x05, 0x4a, 0x98, 0x78, 0x0e, 0xc3, 0x28, 0xd4, 0x04, 0x85, + 0x9c, 0xf6, 0x89, 0xa0, 0x7c, 0xe9, 0x44, 0xca, 0x24, 0xb4, 0xdb, 0xbe, 0x26, 0xe3, 0x2b, 0x81, + 0x19, 0x7a, 0x55, 0xd2, 0xda, 0x64, 0x86, 0x2a, 0xcd, 0xa3, 0xbc, 0xf6, 0x75, 0x9f, 0xd7, 0x66, + 0x13, 0x29, 0x8a, 0xb0, 0x9a, 0x22, 0xb6, 0xaf, 0x4a, 0x62, 0x9b, 0x5b, 0x30, 0x59, 0x8c, 0xd9, + 0xb6, 0x62, 0xcc, 0x36, 0xbf, 0x60, 0x99, 0x09, 0xd4, 0xb6, 0x15, 0xa3, 0xb6, 0x85, 0x05, 0x4e, + 0x12, 0xb8, 0xed, 0xeb, 0x3e, 0xb7, 0x2d, 0x2e, 0x58, 0xf6, 0x14, 0xb9, 0xbd, 0x1b, 0x27, 0xb7, + 0x82, 0x98, 0x3e, 0x93, 0x68, 0x9d, 0xc8, 0x6e, 0xff, 0x37, 0xc2, 0x6e, 0x95, 0x44, 0x6a, 0x29, + 0x9c, 0xcc, 0xa1, 0xb7, 0xad, 0x18, 0xbd, 0x85, 0x05, 0x7b, 0x90, 0xc0, 0x6f, 0xdf, 0x89, 0xf2, + 0xdb, 0x95, 0x44, 0x8a, 0x2c, 0x0f, 0xcd, 0x3c, 0x82, 0xfb, 0x46, 0x40, 0x70, 0x57, 0x13, 0x19, + 0xba, 0x5c, 0xc3, 0x34, 0xc3, 0x3d, 0x98, 0x61, 0xb8, 0x82, 0x91, 0x3e, 0x97, 0xe8, 0x62, 0x01, + 0xc5, 0x3d, 0x98, 0xa1, 0xb8, 0x95, 0x05, 0x0e, 0x17, 0x70, 0xdc, 0x9f, 0xcc, 0xe7, 0xb8, 0xc9, + 0x2c, 0x54, 0x3e, 0xe6, 0x72, 0x24, 0x57, 0x4b, 0x20, 0xb9, 0x82, 0x88, 0xbe, 0x98, 0xe8, 0x7e, + 0x69, 0x96, 0x7b, 0x7f, 0x0e, 0xcb, 0x5d, 0xe3, 0xce, 0x6f, 0x26, 0x3a, 0xbf, 0x08, 0xcd, 0x7d, + 0x81, 0xb1, 0x89, 0x29, 0x3c, 0x62, 0x88, 0x4c, 0x5c, 0xd7, 0x76, 0x25, 0x83, 0x14, 0x1d, 0xf5, + 0x26, 0xe3, 0x37, 0x21, 0xf6, 0x9c, 0x43, 0x89, 0x79, 0xe4, 0x8b, 0xe0, 0x8d, 0xfa, 0xeb, 0x74, + 0x68, 0xcb, 0x29, 0x41, 0x94, 0x1b, 0x29, 0x92, 0x1b, 0x45, 0x98, 0x72, 0x26, 0xce, 0x94, 0x37, + 0x60, 0x85, 0x45, 0xb4, 0x29, 0x12, 0xac, 0x3b, 0x3e, 0x09, 0x46, 0xb7, 0x60, 0x8d, 0x53, 0x16, + 0x81, 0xef, 0x32, 0x8c, 0xe5, 0x38, 0xb8, 0x57, 0xd9, 0x80, 0x38, 0xf3, 0x22, 0x9e, 0xbd, 0x0c, + 0x97, 0x22, 0xba, 0x41, 0xa4, 0x14, 0xcc, 0xaf, 0x16, 0x68, 0xef, 0xc8, 0x90, 0xf9, 0x7e, 0xb8, + 0x41, 0x21, 0xc1, 0x46, 0x90, 0xeb, 0xdb, 0x06, 0x91, 0x71, 0x8c, 0xb7, 0x19, 0xe9, 0x1e, 0xd9, + 0x03, 0x19, 0xad, 0x58, 0x93, 0x69, 0x05, 0xe0, 0xaa, 0x08, 0xec, 0x54, 0x7f, 0x97, 0x0e, 0xfd, + 0x85, 0x9c, 0x7b, 0x1e, 0x3d, 0x4e, 0xff, 0x7b, 0xe8, 0x71, 0xe6, 0x3b, 0xd3, 0xe3, 0x28, 0x8f, + 0xc8, 0xc6, 0x79, 0xc4, 0xdf, 0xd3, 0xe1, 0x1b, 0x0e, 0xc8, 0xee, 0x77, 0xdb, 0x91, 0x90, 0x14, + 0xe4, 0xf9, 0xfb, 0x92, 0xa4, 0x40, 0xa6, 0x30, 0x05, 0x3e, 0x6f, 0x3c, 0x85, 0x29, 0x0a, 0x9a, + 0xc0, 0x3b, 0xe8, 0x36, 0x28, 0xbc, 0x62, 0xa5, 0xd9, 0x8e, 0x27, 0x71, 0xfc, 0xa9, 0xe8, 0x5a, + 0x45, 0x61, 0x6a, 0xf3, 0x90, 0xe9, 0x1c, 0x38, 0x1e, 0x2e, 0x39, 0xb2, 0x15, 0xe1, 0x3b, 0x4a, + 0x8c, 0x76, 0x5f, 0x03, 0x85, 0x3d, 0xbd, 0xe7, 0xe8, 0x7d, 0xc2, 0x31, 0x59, 0xc1, 0xa1, 0x40, + 0x7d, 0x08, 0x68, 0x36, 0x2a, 0xa0, 0x0e, 0x14, 0xc8, 0x09, 0xb1, 0xa8, 0xc7, 0x59, 0xc7, 0x14, + 0x67, 0x90, 0x9c, 0x96, 0x58, 0xb4, 0x59, 0x67, 0x9b, 0xfc, 0xb7, 0xaf, 0x37, 0x6a, 0x42, 0xfb, + 0x25, 0x7b, 0x6c, 0x52, 0x32, 0x76, 0xe8, 0x19, 0x96, 0xf6, 0xea, 0x1f, 0x33, 0x8c, 0x60, 0xc6, + 0x22, 0xc6, 0xdc, 0xbd, 0xf5, 0x2f, 0x50, 0x26, 0x92, 0x5c, 0x2c, 0xb7, 0xdf, 0xeb, 0x00, 0x03, + 0xdd, 0xd3, 0x3e, 0xd5, 0x2d, 0x4a, 0x0c, 0xb9, 0xe9, 0x11, 0x09, 0x6a, 0x40, 0x89, 0xf5, 0x26, + 0x1e, 0x31, 0x64, 0x9e, 0x13, 0xf4, 0x23, 0xeb, 0x2c, 0x7e, 0xbf, 0x75, 0xc6, 0x77, 0xb9, 0x34, + 0xb5, 0xcb, 0x11, 0xf2, 0xa7, 0x44, 0xc9, 0x1f, 0x7b, 0x36, 0xc7, 0x35, 0x6d, 0xd7, 0xa4, 0x67, + 0xfc, 0xd5, 0x64, 0x71, 0xd0, 0x67, 0xe9, 0xf4, 0x98, 0x8c, 0x1d, 0xdb, 0x1e, 0x69, 0x02, 0xbc, + 0x56, 0xb8, 0xe9, 0xaa, 0x14, 0xb6, 0x39, 0x86, 0xfd, 0x3c, 0x13, 0x5e, 0xbf, 0x90, 0xe4, 0xff, + 0xc7, 0x6d, 0xb0, 0xfa, 0x0b, 0x9e, 0xf9, 0xc7, 0x39, 0x01, 0x3a, 0x82, 0xb5, 0xe0, 0xfa, 0x6b, + 0x13, 0x0e, 0x0b, 0xfe, 0x81, 0x5e, 0x16, 0x3f, 0x6a, 0x27, 0x71, 0xb1, 0x87, 0x7e, 0x00, 0x57, + 0xa7, 0xa0, 0x2d, 0x70, 0x9d, 0x59, 0x12, 0xe1, 0x9e, 0x88, 0x23, 0x9c, 0xef, 0x39, 0xdc, 0xab, + 0xec, 0xf7, 0xbc, 0x74, 0xbb, 0x2c, 0x99, 0x8c, 0x32, 0x9c, 0xb9, 0x6f, 0xff, 0x19, 0x28, 0xbb, + 0x84, 0xea, 0xa6, 0xa5, 0xc5, 0xd2, 0xf5, 0x55, 0x21, 0x94, 0x45, 0x80, 0x43, 0x78, 0x62, 0x2e, + 0xd3, 0x41, 0xff, 0x0d, 0x4a, 0x48, 0x92, 0xd2, 0x09, 0x99, 0x6f, 0x90, 0xcd, 0x85, 0xba, 0xea, + 0x6f, 0xd3, 0xa1, 0xcb, 0x78, 0x7e, 0xd8, 0x86, 0x82, 0x4b, 0xbc, 0xc9, 0x48, 0x64, 0x6c, 0x95, + 0xed, 0x97, 0x97, 0xe3, 0x48, 0x4c, 0x3a, 0x19, 0x51, 0x2c, 0x8d, 0xd5, 0x87, 0x50, 0x10, 0x12, + 0xb4, 0x02, 0xc5, 0xfb, 0xfb, 0xf7, 0xf6, 0x0f, 0x3e, 0xd8, 0xaf, 0xa5, 0x10, 0x40, 0x61, 0xa7, + 0xd5, 0x6a, 0x1f, 0x76, 0x6b, 0x69, 0xa4, 0x40, 0x7e, 0xa7, 0x79, 0x80, 0xbb, 0xb5, 0x0c, 0x13, + 0xe3, 0xf6, 0x7b, 0xed, 0x56, 0xb7, 0x96, 0x45, 0x6b, 0x50, 0x16, 0x6d, 0xed, 0xee, 0x01, 0x7e, + 0x7f, 0xa7, 0x5b, 0xcb, 0x45, 0x44, 0x47, 0xed, 0xfd, 0x3b, 0x6d, 0x5c, 0xcb, 0xab, 0xaf, 0xb0, + 0x94, 0x30, 0x81, 0x55, 0x85, 0xc9, 0x5f, 0x3a, 0x92, 0xfc, 0xa9, 0xbf, 0xca, 0x40, 0x23, 0x99, + 0x2a, 0xa1, 0xf7, 0xa6, 0x16, 0xbe, 0x7d, 0x01, 0x9e, 0x35, 0xb5, 0x7a, 0xf4, 0x2c, 0x54, 0x5c, + 0x72, 0x4c, 0x68, 0x7f, 0x28, 0xa8, 0x9b, 0x88, 0x98, 0x65, 0x5c, 0x96, 0x52, 0x6e, 0xe4, 0x09, + 0xb5, 0x8f, 0x49, 0x9f, 0x6a, 0x02, 0x8a, 0xc4, 0xa1, 0x53, 0x98, 0x1a, 0x93, 0x1e, 0x09, 0xa1, + 0xfa, 0xd1, 0x85, 0xf6, 0x52, 0x81, 0x3c, 0x6e, 0x77, 0xf1, 0x0f, 0x6b, 0x59, 0x84, 0xa0, 0xc2, + 0x9b, 0xda, 0xd1, 0xfe, 0xce, 0xe1, 0x51, 0xe7, 0x80, 0xed, 0xe5, 0x25, 0xa8, 0xfa, 0x7b, 0xe9, + 0x0b, 0xf3, 0xea, 0x6d, 0xb8, 0x9a, 0xc0, 0xf3, 0x16, 0xe4, 0xbf, 0xea, 0x3f, 0xd3, 0x50, 0x9d, + 0xba, 0x5a, 0x68, 0x1b, 0xf2, 0x22, 0x71, 0x48, 0xfa, 0x88, 0xc2, 0x91, 0x41, 0xde, 0x43, 0xa1, + 0x8a, 0xde, 0x82, 0x12, 0x91, 0x15, 0x9a, 0x79, 0x57, 0x58, 0xa4, 0xc8, 0x7e, 0x0d, 0x47, 0x9a, + 0x06, 0x16, 0xe8, 0x6d, 0x50, 0x02, 0x8c, 0x90, 0xd9, 0xea, 0xd3, 0x73, 0x32, 0x6c, 0x5f, 0x45, + 0xda, 0x87, 0x36, 0xe8, 0x8d, 0x90, 0x26, 0xe6, 0x66, 0xd3, 0x15, 0x69, 0x2e, 0x14, 0xa4, 0xb1, + 0xaf, 0xaf, 0xb6, 0x60, 0x25, 0xb2, 0x1e, 0xf4, 0x14, 0x28, 0x63, 0xfd, 0x54, 0x56, 0xfe, 0x44, + 0xed, 0xa6, 0x34, 0xd6, 0x4f, 0x45, 0xd1, 0xef, 0x2a, 0x14, 0xd9, 0xe0, 0x40, 0xf7, 0x64, 0x95, + 0xa0, 0x30, 0xd6, 0x4f, 0xdf, 0xd5, 0x3d, 0xf5, 0x43, 0xa8, 0xc4, 0xab, 0x5e, 0xec, 0x0c, 0xbb, + 0xf6, 0xc4, 0x32, 0xb8, 0x8f, 0x3c, 0x16, 0x1d, 0xf4, 0x9a, 0x5f, 0x46, 0xc8, 0x24, 0x5c, 0xf6, + 0x07, 0x36, 0x25, 0x91, 0xaa, 0x99, 0xac, 0x27, 0x3c, 0x86, 0x3c, 0x87, 0x2d, 0x06, 0x41, 0xbc, + 0x7e, 0x25, 0x29, 0x32, 0x6b, 0xa3, 0x0f, 0x01, 0x74, 0x4a, 0x5d, 0xb3, 0x37, 0x09, 0x1d, 0x6f, + 0xcc, 0x87, 0xbd, 0x1d, 0x5f, 0xaf, 0x79, 0x4d, 0xe2, 0xdf, 0xe5, 0xd0, 0x34, 0x82, 0x81, 0x11, + 0x87, 0xea, 0x3e, 0x54, 0xe2, 0xb6, 0xd1, 0x4a, 0xf2, 0xea, 0x9c, 0x4a, 0x72, 0x40, 0xc3, 0x02, + 0x12, 0x97, 0x15, 0xb5, 0x4a, 0xde, 0x51, 0x3f, 0x4b, 0x43, 0xa9, 0x7b, 0x2a, 0x2f, 0x44, 0x42, + 0x99, 0x2c, 0x34, 0xcd, 0x44, 0x8b, 0x42, 0xa2, 0xee, 0x96, 0x0d, 0xaa, 0x79, 0xef, 0x04, 0x57, + 0x3e, 0xb7, 0x6c, 0x9a, 0xec, 0x97, 0x35, 0x25, 0xcc, 0xbd, 0x09, 0x4a, 0x70, 0xaa, 0x58, 0xae, + 0xa1, 0x1b, 0x86, 0x4b, 0x3c, 0x4f, 0xae, 0xcd, 0xef, 0xf2, 0xaa, 0xab, 0xfd, 0xa9, 0x2c, 0x3b, + 0x65, 0xb1, 0xe8, 0xa8, 0x06, 0x54, 0xa7, 0x02, 0x1e, 0x7a, 0x13, 0x8a, 0xce, 0xa4, 0xa7, 0xf9, + 0xdb, 0x33, 0x75, 0x79, 0x7c, 0xde, 0x39, 0xe9, 0x8d, 0xcc, 0xfe, 0x3d, 0x72, 0xe6, 0x3f, 0x8c, + 0x33, 0xe9, 0xdd, 0x13, 0xbb, 0x28, 0x66, 0xc9, 0x44, 0x67, 0x39, 0x81, 0x92, 0x7f, 0x28, 0xd0, + 0xff, 0x45, 0xef, 0x89, 0x5f, 0x8b, 0x4f, 0x0c, 0xc2, 0xd2, 0x7d, 0xe4, 0x9a, 0xdc, 0x82, 0x35, + 0xcf, 0x1c, 0x58, 0xc4, 0xd0, 0xc2, 0x6c, 0x87, 0xcf, 0x56, 0xc2, 0x55, 0x31, 0xb0, 0xe7, 0xa7, + 0x3a, 0xea, 0x3f, 0xd2, 0x50, 0xf2, 0x2f, 0x2c, 0x7a, 0x25, 0x72, 0xee, 0x2a, 0x73, 0x4a, 0x42, + 0xbe, 0x62, 0x58, 0x38, 0x8d, 0x3f, 0x6b, 0xe6, 0xe2, 0xcf, 0x9a, 0x54, 0x01, 0xf7, 0x3f, 0x45, + 0xe4, 0x2e, 0xfc, 0x29, 0xe2, 0x25, 0x40, 0xd4, 0xa6, 0xfa, 0x48, 0x3b, 0xb1, 0xa9, 0x69, 0x0d, + 0x34, 0xb1, 0xd9, 0x82, 0x8b, 0xd5, 0xf8, 0xc8, 0x03, 0x3e, 0x70, 0xc8, 0xf7, 0xfd, 0xa7, 0x69, + 0x28, 0x05, 0x51, 0xf5, 0xa2, 0x75, 0xd0, 0x2b, 0x50, 0x90, 0x81, 0x43, 0x14, 0x42, 0x65, 0x2f, + 0x28, 0xc9, 0xe7, 0x22, 0x25, 0xf9, 0x06, 0x94, 0xc6, 0x84, 0xea, 0x1c, 0x9f, 0x45, 0xc2, 0x19, + 0xf4, 0x6f, 0xbd, 0x01, 0x2b, 0x91, 0x92, 0x34, 0xbb, 0x79, 0xfb, 0xed, 0x0f, 0x6a, 0xa9, 0x46, + 0xf1, 0xb3, 0x2f, 0x6e, 0x64, 0xf7, 0xc9, 0xa7, 0xec, 0xcc, 0xe2, 0x76, 0xab, 0xd3, 0x6e, 0xdd, + 0xab, 0xa5, 0x1b, 0x2b, 0x9f, 0x7d, 0x71, 0xa3, 0x88, 0x09, 0xaf, 0x24, 0xdd, 0xea, 0xc0, 0x6a, + 0xf4, 0xad, 0xc4, 0x63, 0x0f, 0x82, 0xca, 0x9d, 0xfb, 0x87, 0x7b, 0xbb, 0xad, 0x9d, 0x6e, 0x5b, + 0x7b, 0x70, 0xd0, 0x6d, 0xd7, 0xd2, 0xe8, 0x2a, 0x5c, 0xda, 0xdb, 0x7d, 0xb7, 0xd3, 0xd5, 0x5a, + 0x7b, 0xbb, 0xed, 0xfd, 0xae, 0xb6, 0xd3, 0xed, 0xee, 0xb4, 0xee, 0xd5, 0x32, 0xdb, 0x7f, 0x05, + 0xa8, 0xee, 0x34, 0x5b, 0xbb, 0x2c, 0x6e, 0x9a, 0x7d, 0x5d, 0x56, 0xea, 0x72, 0x3c, 0xdf, 0x3f, + 0xf7, 0x0b, 0x7b, 0xe3, 0xfc, 0x42, 0x25, 0xba, 0x0b, 0x79, 0x5e, 0x0a, 0x40, 0xe7, 0x7f, 0x72, + 0x6f, 0x2c, 0xa8, 0x5c, 0xb2, 0x87, 0xe1, 0xd7, 0xe3, 0xdc, 0x6f, 0xf0, 0x8d, 0xf3, 0x0b, 0x99, + 0x08, 0x83, 0x12, 0xe6, 0xf2, 0x8b, 0xbf, 0xc9, 0x37, 0x96, 0x28, 0x6e, 0x32, 0x9f, 0x61, 0x42, + 0xb1, 0xf8, 0x1b, 0x75, 0x63, 0x09, 0x00, 0x43, 0x7b, 0x50, 0xf4, 0x73, 0xc0, 0x45, 0x5f, 0xcd, + 0x1b, 0x0b, 0x0b, 0x8f, 0xec, 0x15, 0x88, 0x5c, 0xfd, 0xfc, 0x5f, 0x00, 0x1a, 0x0b, 0xaa, 0xa8, + 0x68, 0x17, 0x0a, 0x92, 0x25, 0x2f, 0xf8, 0x12, 0xde, 0x58, 0x54, 0x48, 0x64, 0x9b, 0x16, 0x16, + 0x41, 0x16, 0xff, 0xd8, 0xd0, 0x58, 0xa2, 0x40, 0x8c, 0xee, 0x03, 0x44, 0x32, 0xf3, 0x25, 0xfe, + 0x58, 0x68, 0x2c, 0x53, 0xf8, 0x45, 0x07, 0x50, 0x0a, 0x12, 0xa5, 0x85, 0xff, 0x0f, 0x34, 0x16, + 0x57, 0x60, 0xd1, 0x43, 0x28, 0xc7, 0x33, 0x84, 0xe5, 0xfe, 0x0a, 0x68, 0x2c, 0x59, 0x5a, 0x65, + 0xfe, 0xe3, 0xe9, 0xc2, 0x72, 0x7f, 0x09, 0x34, 0x96, 0xac, 0xb4, 0xa2, 0x8f, 0x61, 0x6d, 0x96, + 0xce, 0x2f, 0xff, 0xd3, 0x40, 0xe3, 0x02, 0xb5, 0x57, 0x34, 0x06, 0x34, 0x27, 0x0d, 0xb8, 0xc0, + 0x3f, 0x04, 0x8d, 0x8b, 0x94, 0x62, 0x91, 0x01, 0xd5, 0x69, 0x6e, 0xbd, 0xec, 0x3f, 0x05, 0x8d, + 0xa5, 0xcb, 0xb2, 0xcd, 0xf6, 0x97, 0xdf, 0xac, 0xa7, 0xbf, 0xfa, 0x66, 0x3d, 0xfd, 0xe7, 0x6f, + 0xd6, 0xd3, 0x9f, 0x7f, 0xbb, 0x9e, 0xfa, 0xea, 0xdb, 0xf5, 0xd4, 0x1f, 0xbe, 0x5d, 0x4f, 0xfd, + 0xe8, 0xc5, 0x81, 0x49, 0x87, 0x93, 0xde, 0x66, 0xdf, 0x1e, 0x6f, 0x45, 0x7f, 0xa3, 0x9a, 0xf7, + 0x6b, 0x57, 0xaf, 0xc0, 0xc3, 0xe1, 0xab, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x54, 0x3f, 0x72, + 0x96, 0xfa, 0x25, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -5130,6 +5142,20 @@ func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = 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] = 0x1a + } + } if m.BlockDataSize != 0 { i = encodeVarintTypes(dAtA, i, uint64(m.BlockDataSize)) i-- @@ -7347,6 +7373,12 @@ func (m *RequestPrepareProposal) Size() (n int) { if m.BlockDataSize != 0 { n += 1 + sovTypes(uint64(m.BlockDataSize)) } + if len(m.Votes) > 0 { + for _, e := range m.Votes { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } return n } @@ -10507,6 +10539,40 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { break } } + case 3: + 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, &types1.Vote{}) + 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:]) 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/v1/reactor.go b/blockchain/v1/reactor.go index c4c61ec51..95e165c45 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 } 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 c2792d58b..808b16050 100644 --- a/blockchain/v2/reactor_test.go +++ b/blockchain/v2/reactor_test.go @@ -14,7 +14,7 @@ import ( 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" @@ -301,7 +301,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 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..1f14b11aa 100644 --- a/consensus/byzantine_test.go +++ b/consensus/byzantine_test.go @@ -187,6 +187,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { } var commit *types.Commit + var votes []*types.Vote switch { case lazyProposer.Height == lazyProposer.state.InitialHeight: // We're creating a proposal for the first block. @@ -195,6 +196,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { case lazyProposer.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = lazyProposer.LastCommit.MakeCommit() + votes = lazyProposer.LastCommit.GetVotes() default: // This shouldn't happen. lazyProposer.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block") return @@ -212,7 +214,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { proposerAddr := lazyProposer.privValidatorPubKey.Address() block, blockParts := lazyProposer.blockExec.CreateProposalBlock( - lazyProposer.Height, lazyProposer.state, commit, proposerAddr, + lazyProposer.Height, lazyProposer.state, commit, proposerAddr, votes, ) // Flush the WAL. Otherwise, we may not recompute the same proposal to sign, 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 2970f15ed..a081e262e 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -98,7 +98,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)") } diff --git a/consensus/state.go b/consensus/state.go index 9e6d980a3..d2f3d2b42 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. @@ -1193,6 +1193,7 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa } var commit *types.Commit + var votes []*types.Vote switch { case cs.Height == cs.state.InitialHeight: // We're creating a proposal for the first block. @@ -1202,6 +1203,7 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa case cs.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = cs.LastCommit.MakeCommit() + votes = cs.LastCommit.GetVotes() default: // This shouldn't happen. cs.Logger.Error("propose step; cannot propose anything without commit for the previous block") @@ -1217,7 +1219,7 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa proposerAddr := cs.privValidatorPubKey.Address() - return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr) + return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, votes) } // Enter: `timeoutPropose` after entering Propose. @@ -2034,7 +2036,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/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/node/node_test.go b/node/node_test.go index 9b82d6ca2..5e65ad2b4 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") } @@ -309,6 +309,7 @@ func TestCreateProposalBlock(t *testing.T) { height, state, commit, proposerAddr, + nil, ) // check that the part set does not exceed the maximum block size @@ -387,6 +388,7 @@ func TestMaxProposalBlockSize(t *testing.T) { height, state, commit, proposerAddr, + nil, ) pb, err := block.ToProto() 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 fc3228280..f7c5e2412 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -132,6 +132,9 @@ message RequestPrepareProposal { 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; + // votes includes all votes from the previous block. This contains vote extension data that can be used in proposal + // preparation. The votes here will then form the last commit that gets sent in the proposed block. + repeated types.Vote votes = 3; } //---------------------------------------- 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/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/state/execution.go b/state/execution.go index a6451146d..2e7b4b254 100644 --- a/state/execution.go +++ b/state/execution.go @@ -97,6 +97,7 @@ func (blockExec *BlockExecutor) CreateProposalBlock( height int64, state State, commit *types.Commit, proposerAddr []byte, + votes []*types.Vote, ) (*types.Block, *types.PartSet) { maxBytes := state.ConsensusParams.Block.MaxBytes @@ -110,7 +111,11 @@ func (blockExec *BlockExecutor) CreateProposalBlock( txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas) preparedProposal, err := blockExec.proxyApp.PrepareProposalSync( - abci.RequestPrepareProposal{BlockData: txs.ToSliceOfBytes(), BlockDataSize: maxDataBytes}, + abci.RequestPrepareProposal{ + BlockData: txs.ToSliceOfBytes(), + BlockDataSize: maxDataBytes, + Votes: types.VotesToProto(votes), + }, ) if err != nil { // The App MUST ensure that only valid (and hence 'processable') transactions diff --git a/state/execution_test.go b/state/execution_test.go index 3d7fa93ab..a8aeffe93 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -408,7 +408,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.") } diff --git a/state/state_test.go b/state/state_test.go index b4e33626a..3f27efe42 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -41,7 +41,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) 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/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..b9b208faa 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 @@ -1265,6 +1265,7 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa } var commit *types.Commit + var votes []*types.Vote switch { case cs.Height == cs.state.InitialHeight: // We're creating a proposal for the first block. @@ -1273,6 +1274,7 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa case cs.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = cs.LastCommit.MakeCommit() + votes = cs.LastCommit.GetVotes() default: // This shouldn't happen. cs.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block") return @@ -1286,7 +1288,7 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa } proposerAddr := cs.privValidatorPubKey.Address() - return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr) + return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, votes) } // Enter: any +2/3 prevotes at next round. diff --git a/types/block.go b/types/block.go index da0e78cf2..2f0cc487b 100644 --- a/types/block.go +++ b/types/block.go @@ -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/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..2d6a64ece 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -226,6 +226,10 @@ func (voteSet *VoteSet) getVote(valIndex int32, blockKey string) (vote *Vote, ok return nil, false } +func (voteSet *VoteSet) GetVotes() []*Vote { + return voteSet.votes +} + // Assumes signature is valid. // If conflicting vote exists, returns it. func (voteSet *VoteSet) addVerifiedVote( 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 From d268e563838afc84e52eb5eb8567c067a7f11cfd Mon Sep 17 00:00:00 2001 From: Sergio Mena Date: Wed, 3 Aug 2022 17:24:24 +0200 Subject: [PATCH 3/4] Sync PrepareProposal with Spec. Main part (#9158) * ----start---- * [PARTIAL cherry-pick] ABCI Vote Extension 2 (#6885) * Cherry-picked #6567: state/types: refactor makeBlock, makeBlocks and makeTxs (#6567) * [Cherrypicked] types: remove panic from block methods (#7501) * [cherrypicked] abci++: synchronize PrepareProposal with the newest version of the spec (#8094) This change implements the logic for the PrepareProposal ABCI++ method call. The main logic for creating and issuing the PrepareProposal request lives in execution.go and is tested in a set of new tests in execution_test.go. This change also updates the mempool mock to use a mockery generated version and removes much of the plumbing for the no longer used ABCIResponses. * make proto-gen * Backported EvidenceList's method ToABCI from #7961 * make build * Fix mockery for Mempool * mockery * Backported abci Application mocks from #7961 * mockery2 * Fixed new PrepareProposal test cases in state/execution_test.go * Fixed returned errors in consensus/state.go * lint * Addressed @cmwaters' comment Co-authored-by: mconcat Co-authored-by: JayT106 Co-authored-by: Sam Kleinman Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> --- abci/example/kvstore/kvstore.go | 3 +- abci/example/kvstore/persistent_kvstore.go | 53 +- abci/types/application.go | 5 +- abci/types/mocks/application.go | 224 +++ abci/types/mocks/base.go | 176 +++ abci/types/{result.go => types.go} | 0 abci/types/types.pb.go | 1521 ++++++++++++++++---- blockchain/v0/reactor.go | 10 +- blockchain/v0/reactor_test.go | 55 +- blockchain/v1/reactor.go | 8 +- blockchain/v1/reactor_test.go | 38 +- blockchain/v2/processor.go | 11 +- blockchain/v2/reactor_test.go | 62 +- consensus/byzantine_test.go | 20 +- consensus/common_test.go | 6 +- consensus/mempool_test.go | 2 +- consensus/replay_test.go | 147 +- consensus/state.go | 27 +- consensus/state_test.go | 141 +- evidence/mocks/block_store.go | 1 - evidence/pool_test.go | 31 +- mempool/mempool.go | 2 + mempool/mock/mempool.go | 43 - mempool/mocks/mempool.go | 184 +++ node/node_test.go | 12 +- proto/tendermint/abci/types.proto | 45 +- proxy/mocks/app_conn_consensus.go | 1 - proxy/mocks/app_conn_mempool.go | 1 - rpc/client/helpers.go | 2 +- rpc/core/tx.go | 13 +- state/execution.go | 71 +- state/execution_test.go | 282 +++- state/helpers_test.go | 44 +- state/mocks/evidence_pool.go | 1 - state/mocks/store.go | 1 - state/state.go | 4 +- state/state_test.go | 84 +- state/test/factory/block.go | 75 + state/txindex/mocks/tx_indexer.go | 1 - state/validation_test.go | 58 +- statesync/mocks/state_provider.go | 1 - store/store_test.go | 45 +- test/e2e/app/app.go | 3 +- test/factory/tx.go | 16 + test/maverick/consensus/state.go | 29 +- types/block.go | 10 +- types/block_test.go | 15 +- types/evidence.go | 10 + types/evidence_test.go | 5 +- types/tx.go | 223 ++- types/tx_test.go | 165 ++- types/vote_set.go | 4 + 52 files changed, 3199 insertions(+), 792 deletions(-) create mode 100644 abci/types/mocks/application.go create mode 100644 abci/types/mocks/base.go rename abci/types/{result.go => types.go} (100%) delete mode 100644 mempool/mock/mempool.go create mode 100644 mempool/mocks/mempool.go create mode 100644 state/test/factory/block.go create mode 100644 test/factory/tx.go diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index b76699097..d2b3f5d44 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -173,6 +173,5 @@ func (app *Application) Query(reqQuery types.RequestQuery) (resQuery types.Respo func (app *Application) PrepareProposal( req types.RequestPrepareProposal) types.ResponsePrepareProposal { - return types.ResponsePrepareProposal{ - BlockData: req.BlockData} + return types.ResponsePrepareProposal{} } diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index 320f25502..465848f2a 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)} } //--------------------------------------------- @@ -293,3 +293,46 @@ 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 strips. +// It marks all of the original transactions as 'REMOVED' so that +// Tendermint will remove them from its mempool. +func (app *PersistentKVStoreApplication) substPrepareTx(blockData [][]byte) []*types.TxRecord { + trs := make([]*types.TxRecord, len(blockData)) + var removed []*types.TxRecord + for i, tx := range blockData { + if isPrepareTx(tx) { + removed = append(removed, &types.TxRecord{ + Tx: tx, + Action: types.TxRecord_REMOVED, + }) + trs[i] = &types.TxRecord{ + Tx: bytes.TrimPrefix(tx, []byte(PreparePrefix)), + Action: types.TxRecord_ADDED, + } + continue + } + trs[i] = &types.TxRecord{ + Tx: tx, + Action: types.TxRecord_UNMODIFIED, + } + } + + return append(trs, removed...) +} diff --git a/abci/types/application.go b/abci/types/application.go index fe69b6f05..47286e373 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -4,6 +4,7 @@ import ( context "golang.org/x/net/context" ) +//go:generate mockery --case underscore --name Application // Application is an interface that enables any finite, deterministic state machine // to be driven by a blockchain-based replication engine via the ABCI. // All methods take a RequestXxx argument and return a ResponseXxx argument, @@ -97,9 +98,7 @@ func (BaseApplication) ApplySnapshotChunk(req RequestApplySnapshotChunk) Respons } func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepareProposal { - return ResponsePrepareProposal{ - BlockData: req.BlockData, - } + return ResponsePrepareProposal{} } //------------------------------------------------------- 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 957a99c1c..2fd9ed1a5 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -160,6 +160,38 @@ func (ResponseApplySnapshotChunk_Result) EnumDescriptor() ([]byte, []int) { return fileDescriptor_252557cfdd89a31a, []int{33, 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 @@ -1229,15 +1261,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"` - // votes includes all votes from the previous block. This contains vote extension data that can be used in proposal - // preparation. The votes here will then form the last commit that gets sent in the proposed block. - Votes []*types1.Vote `protobuf:"bytes,3,rep,name=votes,proto3" json:"votes,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{} } @@ -1273,27 +1305,48 @@ 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 } -func (m *RequestPrepareProposal) GetVotes() []*types1.Vote { - if m != nil { - return m.Votes - } - return nil -} - type Response struct { // Types that are valid to be assigned to Value: // *Response_Exception @@ -2582,7 +2635,8 @@ func (m *ResponseApplySnapshotChunk) GetRejectSenders() []string { } type ResponsePrepareProposal struct { - BlockData [][]byte `protobuf:"bytes,1,rep,name=block_data,json=blockData,proto3" json:"block_data,omitempty"` + ModifiedTx bool `protobuf:"varint,1,opt,name=modified_tx,json=modifiedTx,proto3" json:"modified_tx,omitempty"` + TxRecords []*TxRecord `protobuf:"bytes,2,rep,name=tx_records,json=txRecords,proto3" json:"tx_records,omitempty"` } func (m *ResponsePrepareProposal) Reset() { *m = ResponsePrepareProposal{} } @@ -2618,9 +2672,16 @@ func (m *ResponsePrepareProposal) XXX_DiscardUnknown() { var xxx_messageInfo_ResponsePrepareProposal proto.InternalMessageInfo -func (m *ResponsePrepareProposal) GetBlockData() [][]byte { +func (m *ResponsePrepareProposal) GetModifiedTx() bool { if m != nil { - return m.BlockData + return m.ModifiedTx + } + return false +} + +func (m *ResponsePrepareProposal) GetTxRecords() []*TxRecord { + if m != nil { + return m.TxRecords } return nil } @@ -2802,6 +2863,58 @@ func (m *LastCommitInfo) 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. @@ -2814,7 +2927,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{38} + return fileDescriptor_252557cfdd89a31a, []int{39} } func (m *Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2868,7 +2981,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{39} + return fileDescriptor_252557cfdd89a31a, []int{40} } func (m *EventAttribute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2932,7 +3045,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{40} + return fileDescriptor_252557cfdd89a31a, []int{41} } func (m *TxResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2989,6 +3102,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"` @@ -3000,7 +3165,7 @@ func (m *Validator) Reset() { *m = Validator{} } func (m *Validator) String() string { return proto.CompactTextString(m) } func (*Validator) ProtoMessage() {} func (*Validator) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{41} + return fileDescriptor_252557cfdd89a31a, []int{43} } func (m *Validator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3053,7 +3218,7 @@ func (m *ValidatorUpdate) Reset() { *m = ValidatorUpdate{} } func (m *ValidatorUpdate) String() string { return proto.CompactTextString(m) } func (*ValidatorUpdate) ProtoMessage() {} func (*ValidatorUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{42} + return fileDescriptor_252557cfdd89a31a, []int{44} } func (m *ValidatorUpdate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3106,7 +3271,7 @@ func (m *VoteInfo) Reset() { *m = VoteInfo{} } func (m *VoteInfo) String() string { return proto.CompactTextString(m) } func (*VoteInfo) ProtoMessage() {} func (*VoteInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{43} + return fileDescriptor_252557cfdd89a31a, []int{45} } func (m *VoteInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3149,6 +3314,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 @@ -3167,7 +3392,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{44} + return fileDescriptor_252557cfdd89a31a, []int{47} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3243,7 +3468,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{45} + return fileDescriptor_252557cfdd89a31a, []int{48} } func (m *Snapshot) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3312,6 +3537,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.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") @@ -3350,12 +3576,15 @@ func init() { proto.RegisterType((*ConsensusParams)(nil), "tendermint.abci.ConsensusParams") proto.RegisterType((*BlockParams)(nil), "tendermint.abci.BlockParams") proto.RegisterType((*LastCommitInfo)(nil), "tendermint.abci.LastCommitInfo") + 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") } @@ -3363,190 +3592,201 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 2917 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x4b, 0x93, 0x23, 0xc5, - 0xb5, 0xd6, 0x5b, 0xaa, 0xd3, 0xad, 0x47, 0xe7, 0x0c, 0x33, 0x42, 0xcc, 0x74, 0x0f, 0x45, 0x00, - 0xc3, 0x00, 0xdd, 0x97, 0x26, 0xe0, 0x0e, 0x17, 0xee, 0x85, 0x96, 0x46, 0x83, 0x9a, 0x69, 0xba, - 0xfb, 0x66, 0x6b, 0x06, 0xbf, 0x98, 0xa2, 0xa4, 0xca, 0x96, 0x8a, 0x91, 0xaa, 0x8a, 0xaa, 0x54, - 0xd3, 0x3d, 0x4b, 0x87, 0xbd, 0xc1, 0xe1, 0x08, 0x96, 0xde, 0xf0, 0x3f, 0xbc, 0x70, 0x78, 0xe3, - 0x0d, 0x11, 0xde, 0xb0, 0xf4, 0xc2, 0x81, 0x1d, 0xb0, 0x70, 0xd8, 0x7f, 0xc0, 0x2b, 0x87, 0x1d, - 0xf9, 0xa8, 0x97, 0xa4, 0x6a, 0xa9, 0xc1, 0x3b, 0xef, 0x32, 0x4f, 0x9e, 0x73, 0xb2, 0x32, 0x2b, - 0xf3, 0x3b, 0xdf, 0x39, 0x55, 0xf0, 0x14, 0x25, 0x96, 0x41, 0xdc, 0xb1, 0x69, 0xd1, 0x2d, 0xbd, - 0xd7, 0x37, 0xb7, 0xe8, 0x99, 0x43, 0xbc, 0x4d, 0xc7, 0xb5, 0xa9, 0x8d, 0xaa, 0xe1, 0xe0, 0x26, - 0x1b, 0x6c, 0x5c, 0x8f, 0x68, 0xf7, 0xdd, 0x33, 0x87, 0xda, 0x5b, 0x8e, 0x6b, 0xdb, 0xc7, 0x42, - 0xbf, 0x71, 0x2d, 0x32, 0xcc, 0xfd, 0x44, 0xbd, 0xc5, 0x46, 0xa5, 0xf1, 0x23, 0x72, 0xe6, 0x8f, - 0x5e, 0x9f, 0xb1, 0x75, 0x74, 0x57, 0x1f, 0xfb, 0xc3, 0x1b, 0x03, 0xdb, 0x1e, 0x8c, 0xc8, 0x16, - 0xef, 0xf5, 0x26, 0xc7, 0x5b, 0xd4, 0x1c, 0x13, 0x8f, 0xea, 0x63, 0x47, 0x2a, 0x5c, 0x1e, 0xd8, - 0x03, 0x9b, 0x37, 0xb7, 0x58, 0x4b, 0x48, 0xd5, 0xbf, 0x94, 0xa0, 0x88, 0xc9, 0x27, 0x13, 0xe2, - 0x51, 0xb4, 0x0d, 0x39, 0xd2, 0x1f, 0xda, 0xf5, 0xf4, 0x8d, 0xf4, 0xcd, 0x95, 0xed, 0x6b, 0x9b, - 0x53, 0x8b, 0xdb, 0x94, 0x7a, 0xed, 0xfe, 0xd0, 0xee, 0xa4, 0x30, 0xd7, 0x45, 0xaf, 0x41, 0xfe, - 0x78, 0x34, 0xf1, 0x86, 0xf5, 0x0c, 0x37, 0xba, 0x9e, 0x64, 0x74, 0x97, 0x29, 0x75, 0x52, 0x58, - 0x68, 0xb3, 0xa9, 0x4c, 0xeb, 0xd8, 0xae, 0x67, 0xcf, 0x9f, 0x6a, 0xd7, 0x3a, 0xe6, 0x53, 0x31, - 0x5d, 0xd4, 0x04, 0xf0, 0x08, 0xd5, 0x6c, 0x87, 0x9a, 0xb6, 0x55, 0xcf, 0x71, 0xcb, 0xa7, 0x93, - 0x2c, 0x8f, 0x08, 0x3d, 0xe0, 0x8a, 0x9d, 0x14, 0x56, 0x3c, 0xbf, 0xc3, 0x7c, 0x98, 0x96, 0x49, - 0xb5, 0xfe, 0x50, 0x37, 0xad, 0x7a, 0xfe, 0x7c, 0x1f, 0xbb, 0x96, 0x49, 0x5b, 0x4c, 0x91, 0xf9, - 0x30, 0xfd, 0x0e, 0x5b, 0xf2, 0x27, 0x13, 0xe2, 0x9e, 0xd5, 0x0b, 0xe7, 0x2f, 0xf9, 0xff, 0x99, - 0x12, 0x5b, 0x32, 0xd7, 0x46, 0x6d, 0x58, 0xe9, 0x91, 0x81, 0x69, 0x69, 0xbd, 0x91, 0xdd, 0x7f, - 0x54, 0x2f, 0x72, 0x63, 0x35, 0xc9, 0xb8, 0xc9, 0x54, 0x9b, 0x4c, 0xb3, 0x93, 0xc2, 0xd0, 0x0b, - 0x7a, 0xe8, 0x2d, 0x28, 0xf5, 0x87, 0xa4, 0xff, 0x48, 0xa3, 0xa7, 0xf5, 0x12, 0xf7, 0xb1, 0x91, - 0xe4, 0xa3, 0xc5, 0xf4, 0xba, 0xa7, 0x9d, 0x14, 0x2e, 0xf6, 0x45, 0x93, 0xad, 0xdf, 0x20, 0x23, - 0xf3, 0x84, 0xb8, 0xcc, 0x5e, 0x39, 0x7f, 0xfd, 0x77, 0x84, 0x26, 0xf7, 0xa0, 0x18, 0x7e, 0x07, - 0xbd, 0x0d, 0x0a, 0xb1, 0x0c, 0xb9, 0x0c, 0xe0, 0x2e, 0x6e, 0x24, 0x9e, 0x15, 0xcb, 0xf0, 0x17, - 0x51, 0x22, 0xb2, 0x8d, 0x6e, 0x43, 0xa1, 0x6f, 0x8f, 0xc7, 0x26, 0xad, 0xaf, 0x70, 0xeb, 0xf5, - 0xc4, 0x05, 0x70, 0xad, 0x4e, 0x0a, 0x4b, 0x7d, 0xb4, 0x0f, 0x95, 0x91, 0xe9, 0x51, 0xcd, 0xb3, - 0x74, 0xc7, 0x1b, 0xda, 0xd4, 0xab, 0xaf, 0x72, 0x0f, 0xcf, 0x26, 0x79, 0xd8, 0x33, 0x3d, 0x7a, - 0xe4, 0x2b, 0x77, 0x52, 0xb8, 0x3c, 0x8a, 0x0a, 0x98, 0x3f, 0xfb, 0xf8, 0x98, 0xb8, 0x81, 0xc3, - 0x7a, 0xf9, 0x7c, 0x7f, 0x07, 0x4c, 0xdb, 0xb7, 0x67, 0xfe, 0xec, 0xa8, 0x00, 0xfd, 0x18, 0x2e, - 0x8d, 0x6c, 0xdd, 0x08, 0xdc, 0x69, 0xfd, 0xe1, 0xc4, 0x7a, 0x54, 0xaf, 0x70, 0xa7, 0x2f, 0x24, - 0x3e, 0xa4, 0xad, 0x1b, 0xbe, 0x8b, 0x16, 0x33, 0xe8, 0xa4, 0xf0, 0xda, 0x68, 0x5a, 0x88, 0x1e, - 0xc2, 0x65, 0xdd, 0x71, 0x46, 0x67, 0xd3, 0xde, 0xab, 0xdc, 0xfb, 0xad, 0x24, 0xef, 0x3b, 0xcc, - 0x66, 0xda, 0x3d, 0xd2, 0x67, 0xa4, 0xa8, 0x0b, 0x35, 0xc7, 0x25, 0x8e, 0xee, 0x12, 0xcd, 0x71, - 0x6d, 0xc7, 0xf6, 0xf4, 0x51, 0xbd, 0xc6, 0x7d, 0x3f, 0x9f, 0xe4, 0xfb, 0x50, 0xe8, 0x1f, 0x4a, - 0xf5, 0x4e, 0x0a, 0x57, 0x9d, 0xb8, 0xa8, 0x59, 0x84, 0xfc, 0x89, 0x3e, 0x9a, 0x10, 0xf5, 0x79, - 0x58, 0x89, 0x00, 0x08, 0xaa, 0x43, 0x71, 0x4c, 0x3c, 0x4f, 0x1f, 0x10, 0x8e, 0x37, 0x0a, 0xf6, - 0xbb, 0x6a, 0x05, 0x56, 0xa3, 0xa0, 0xa1, 0x8e, 0x03, 0x43, 0x06, 0x07, 0xcc, 0xf0, 0x84, 0xb8, - 0x1e, 0xc3, 0x00, 0x69, 0x28, 0xbb, 0xe8, 0x19, 0x28, 0xf3, 0x43, 0xa9, 0xf9, 0xe3, 0x0c, 0x93, - 0x72, 0x78, 0x95, 0x0b, 0x1f, 0x48, 0xa5, 0x0d, 0x58, 0x71, 0xb6, 0x9d, 0x40, 0x25, 0xcb, 0x55, - 0xc0, 0xd9, 0x76, 0xa4, 0x82, 0xfa, 0x3f, 0x50, 0x9b, 0xc6, 0x10, 0x54, 0x83, 0xec, 0x23, 0x72, - 0x26, 0xe7, 0x63, 0x4d, 0x74, 0x59, 0x2e, 0x8b, 0xcf, 0xa1, 0x60, 0xb9, 0xc6, 0xdf, 0x67, 0x02, - 0xe3, 0x00, 0x3c, 0xd0, 0x6d, 0xc8, 0x31, 0x2c, 0x96, 0xb0, 0xda, 0xd8, 0x14, 0x40, 0xbd, 0xe9, - 0x03, 0xf5, 0x66, 0xd7, 0x07, 0xea, 0x66, 0xe9, 0xcb, 0xaf, 0x37, 0x52, 0x9f, 0xff, 0x69, 0x23, - 0x8d, 0xb9, 0x05, 0x7a, 0x92, 0xdd, 0x75, 0xdd, 0xb4, 0x34, 0xd3, 0x90, 0xf3, 0x14, 0x79, 0x7f, - 0xd7, 0x40, 0xf7, 0xa0, 0xd6, 0xb7, 0x2d, 0x8f, 0x58, 0xde, 0xc4, 0xd3, 0x44, 0x20, 0x90, 0x60, - 0x3a, 0x7b, 0x17, 0x5b, 0xbe, 0xe2, 0x21, 0xd7, 0xc3, 0xd5, 0x7e, 0x5c, 0x80, 0xee, 0x02, 0x9c, - 0xe8, 0x23, 0xd3, 0xd0, 0xa9, 0xed, 0x7a, 0xf5, 0xdc, 0x8d, 0xec, 0x5c, 0x37, 0x0f, 0x7c, 0x95, - 0xfb, 0x8e, 0xa1, 0x53, 0xd2, 0xcc, 0xb1, 0xa7, 0xc5, 0x11, 0x4b, 0xf4, 0x1c, 0x54, 0x75, 0xc7, - 0xd1, 0x3c, 0xaa, 0x53, 0xa2, 0xf5, 0xce, 0x28, 0xf1, 0x38, 0xc4, 0xae, 0xe2, 0xb2, 0xee, 0x38, - 0x47, 0x4c, 0xda, 0x64, 0x42, 0xf4, 0x2c, 0x54, 0x18, 0x9c, 0x9a, 0xfa, 0x48, 0x1b, 0x12, 0x73, - 0x30, 0xa4, 0x1c, 0x4a, 0xb3, 0xb8, 0x2c, 0xa5, 0x1d, 0x2e, 0x54, 0x8d, 0xe0, 0x20, 0x70, 0x28, - 0x45, 0x08, 0x72, 0x86, 0x4e, 0x75, 0xbe, 0x91, 0xab, 0x98, 0xb7, 0x99, 0xcc, 0xd1, 0xe9, 0x50, - 0x6e, 0x0f, 0x6f, 0xa3, 0x2b, 0x50, 0x90, 0x6e, 0xb3, 0xdc, 0xad, 0xec, 0xb1, 0x77, 0xe6, 0xb8, - 0xf6, 0x09, 0xe1, 0xb1, 0xa3, 0x84, 0x45, 0x47, 0xfd, 0x59, 0x06, 0xd6, 0x66, 0x40, 0x97, 0xf9, - 0x1d, 0xea, 0xde, 0xd0, 0x9f, 0x8b, 0xb5, 0xd1, 0xeb, 0xcc, 0xaf, 0x6e, 0x10, 0x57, 0x06, 0xbb, - 0x7a, 0x74, 0x8b, 0x44, 0x20, 0xef, 0xf0, 0x71, 0xb9, 0x35, 0x52, 0x1b, 0x1d, 0x40, 0x6d, 0xa4, - 0x7b, 0x54, 0x13, 0x20, 0xa6, 0x45, 0x02, 0xdf, 0x2c, 0x74, 0xef, 0xe9, 0x3e, 0xec, 0xb1, 0xc3, - 0x2e, 0x1d, 0x55, 0x46, 0x31, 0x29, 0xc2, 0x70, 0xb9, 0x77, 0xf6, 0x58, 0xb7, 0xa8, 0x69, 0x11, - 0x6d, 0xe6, 0xcd, 0x3d, 0x39, 0xe3, 0xb4, 0x7d, 0x62, 0x1a, 0xc4, 0xea, 0xfb, 0xaf, 0xec, 0x52, - 0x60, 0x1c, 0xbc, 0x52, 0x4f, 0xc5, 0x50, 0x89, 0x87, 0x0d, 0x54, 0x81, 0x0c, 0x3d, 0x95, 0x1b, - 0x90, 0xa1, 0xa7, 0xe8, 0xbf, 0x20, 0xc7, 0x16, 0xc9, 0x17, 0x5f, 0x99, 0x13, 0xb3, 0xa5, 0x5d, - 0xf7, 0xcc, 0x21, 0x98, 0x6b, 0xaa, 0x6a, 0x70, 0x1b, 0x82, 0x50, 0x32, 0xed, 0x55, 0x7d, 0x01, - 0xaa, 0x53, 0xb1, 0x22, 0xf2, 0xfe, 0xd2, 0xd1, 0xf7, 0xa7, 0x56, 0xa1, 0x1c, 0x0b, 0x0c, 0xea, - 0x15, 0xb8, 0x3c, 0x0f, 0xe7, 0xd5, 0x61, 0x20, 0x8f, 0xe1, 0x35, 0x7a, 0x0d, 0x4a, 0x01, 0xd0, - 0x8b, 0xdb, 0x38, 0xbb, 0x57, 0xbe, 0x32, 0x0e, 0x54, 0xd9, 0x35, 0x64, 0xc7, 0x9a, 0x9f, 0x87, - 0x0c, 0x7f, 0xf0, 0xa2, 0xee, 0x38, 0x1d, 0xdd, 0x1b, 0xaa, 0x1f, 0x41, 0x3d, 0x09, 0xc4, 0xa7, - 0x96, 0x91, 0x0b, 0x8e, 0xe1, 0x15, 0x28, 0x1c, 0xdb, 0xee, 0x58, 0xa7, 0xdc, 0x59, 0x19, 0xcb, - 0x1e, 0x3b, 0x9e, 0x02, 0xd0, 0xb3, 0x5c, 0x2c, 0x3a, 0xaa, 0x06, 0x4f, 0x26, 0x02, 0x39, 0x33, - 0x31, 0x2d, 0x83, 0x88, 0xfd, 0x2c, 0x63, 0xd1, 0x09, 0x1d, 0x89, 0x87, 0x15, 0x1d, 0x36, 0xad, - 0xc7, 0xd7, 0xca, 0xfd, 0x2b, 0x58, 0xf6, 0xd4, 0x5f, 0xa6, 0xe1, 0xca, 0x7c, 0x38, 0x47, 0xd7, - 0x01, 0x04, 0xa0, 0xca, 0x6b, 0x97, 0xbd, 0xb9, 0x8a, 0x15, 0x2e, 0xb9, 0xc3, 0xee, 0xde, 0x73, - 0x50, 0x0d, 0x87, 0x35, 0xcf, 0x7c, 0x2c, 0xce, 0x46, 0x16, 0x97, 0x03, 0x9d, 0x23, 0xf3, 0x31, - 0x41, 0x2f, 0x41, 0xfe, 0xc4, 0x66, 0x60, 0x90, 0xe5, 0xe7, 0xf3, 0xca, 0xec, 0xb5, 0x79, 0x60, - 0x53, 0x82, 0x85, 0x92, 0xfa, 0x1b, 0x05, 0x4a, 0x98, 0x78, 0x0e, 0xc3, 0x28, 0xd4, 0x04, 0x85, - 0x9c, 0xf6, 0x89, 0xa0, 0x7c, 0xe9, 0x44, 0xca, 0x24, 0xb4, 0xdb, 0xbe, 0x26, 0xe3, 0x2b, 0x81, - 0x19, 0x7a, 0x55, 0xd2, 0xda, 0x64, 0x86, 0x2a, 0xcd, 0xa3, 0xbc, 0xf6, 0x75, 0x9f, 0xd7, 0x66, - 0x13, 0x29, 0x8a, 0xb0, 0x9a, 0x22, 0xb6, 0xaf, 0x4a, 0x62, 0x9b, 0x5b, 0x30, 0x59, 0x8c, 0xd9, - 0xb6, 0x62, 0xcc, 0x36, 0xbf, 0x60, 0x99, 0x09, 0xd4, 0xb6, 0x15, 0xa3, 0xb6, 0x85, 0x05, 0x4e, - 0x12, 0xb8, 0xed, 0xeb, 0x3e, 0xb7, 0x2d, 0x2e, 0x58, 0xf6, 0x14, 0xb9, 0xbd, 0x1b, 0x27, 0xb7, - 0x82, 0x98, 0x3e, 0x93, 0x68, 0x9d, 0xc8, 0x6e, 0xff, 0x37, 0xc2, 0x6e, 0x95, 0x44, 0x6a, 0x29, - 0x9c, 0xcc, 0xa1, 0xb7, 0xad, 0x18, 0xbd, 0x85, 0x05, 0x7b, 0x90, 0xc0, 0x6f, 0xdf, 0x89, 0xf2, - 0xdb, 0x95, 0x44, 0x8a, 0x2c, 0x0f, 0xcd, 0x3c, 0x82, 0xfb, 0x46, 0x40, 0x70, 0x57, 0x13, 0x19, - 0xba, 0x5c, 0xc3, 0x34, 0xc3, 0x3d, 0x98, 0x61, 0xb8, 0x82, 0x91, 0x3e, 0x97, 0xe8, 0x62, 0x01, - 0xc5, 0x3d, 0x98, 0xa1, 0xb8, 0x95, 0x05, 0x0e, 0x17, 0x70, 0xdc, 0x9f, 0xcc, 0xe7, 0xb8, 0xc9, - 0x2c, 0x54, 0x3e, 0xe6, 0x72, 0x24, 0x57, 0x4b, 0x20, 0xb9, 0x82, 0x88, 0xbe, 0x98, 0xe8, 0x7e, - 0x69, 0x96, 0x7b, 0x7f, 0x0e, 0xcb, 0x5d, 0xe3, 0xce, 0x6f, 0x26, 0x3a, 0xbf, 0x08, 0xcd, 0x7d, - 0x81, 0xb1, 0x89, 0x29, 0x3c, 0x62, 0x88, 0x4c, 0x5c, 0xd7, 0x76, 0x25, 0x83, 0x14, 0x1d, 0xf5, - 0x26, 0xe3, 0x37, 0x21, 0xf6, 0x9c, 0x43, 0x89, 0x79, 0xe4, 0x8b, 0xe0, 0x8d, 0xfa, 0xeb, 0x74, - 0x68, 0xcb, 0x29, 0x41, 0x94, 0x1b, 0x29, 0x92, 0x1b, 0x45, 0x98, 0x72, 0x26, 0xce, 0x94, 0x37, - 0x60, 0x85, 0x45, 0xb4, 0x29, 0x12, 0xac, 0x3b, 0x3e, 0x09, 0x46, 0xb7, 0x60, 0x8d, 0x53, 0x16, - 0x81, 0xef, 0x32, 0x8c, 0xe5, 0x38, 0xb8, 0x57, 0xd9, 0x80, 0x38, 0xf3, 0x22, 0x9e, 0xbd, 0x0c, - 0x97, 0x22, 0xba, 0x41, 0xa4, 0x14, 0xcc, 0xaf, 0x16, 0x68, 0xef, 0xc8, 0x90, 0xf9, 0x7e, 0xb8, - 0x41, 0x21, 0xc1, 0x46, 0x90, 0xeb, 0xdb, 0x06, 0x91, 0x71, 0x8c, 0xb7, 0x19, 0xe9, 0x1e, 0xd9, - 0x03, 0x19, 0xad, 0x58, 0x93, 0x69, 0x05, 0xe0, 0xaa, 0x08, 0xec, 0x54, 0x7f, 0x97, 0x0e, 0xfd, - 0x85, 0x9c, 0x7b, 0x1e, 0x3d, 0x4e, 0xff, 0x7b, 0xe8, 0x71, 0xe6, 0x3b, 0xd3, 0xe3, 0x28, 0x8f, - 0xc8, 0xc6, 0x79, 0xc4, 0xdf, 0xd3, 0xe1, 0x1b, 0x0e, 0xc8, 0xee, 0x77, 0xdb, 0x91, 0x90, 0x14, - 0xe4, 0xf9, 0xfb, 0x92, 0xa4, 0x40, 0xa6, 0x30, 0x05, 0x3e, 0x6f, 0x3c, 0x85, 0x29, 0x0a, 0x9a, - 0xc0, 0x3b, 0xe8, 0x36, 0x28, 0xbc, 0x62, 0xa5, 0xd9, 0x8e, 0x27, 0x71, 0xfc, 0xa9, 0xe8, 0x5a, - 0x45, 0x61, 0x6a, 0xf3, 0x90, 0xe9, 0x1c, 0x38, 0x1e, 0x2e, 0x39, 0xb2, 0x15, 0xe1, 0x3b, 0x4a, - 0x8c, 0x76, 0x5f, 0x03, 0x85, 0x3d, 0xbd, 0xe7, 0xe8, 0x7d, 0xc2, 0x31, 0x59, 0xc1, 0xa1, 0x40, - 0x7d, 0x08, 0x68, 0x36, 0x2a, 0xa0, 0x0e, 0x14, 0xc8, 0x09, 0xb1, 0xa8, 0xc7, 0x59, 0xc7, 0x14, - 0x67, 0x90, 0x9c, 0x96, 0x58, 0xb4, 0x59, 0x67, 0x9b, 0xfc, 0xb7, 0xaf, 0x37, 0x6a, 0x42, 0xfb, - 0x25, 0x7b, 0x6c, 0x52, 0x32, 0x76, 0xe8, 0x19, 0x96, 0xf6, 0xea, 0x1f, 0x33, 0x8c, 0x60, 0xc6, - 0x22, 0xc6, 0xdc, 0xbd, 0xf5, 0x2f, 0x50, 0x26, 0x92, 0x5c, 0x2c, 0xb7, 0xdf, 0xeb, 0x00, 0x03, - 0xdd, 0xd3, 0x3e, 0xd5, 0x2d, 0x4a, 0x0c, 0xb9, 0xe9, 0x11, 0x09, 0x6a, 0x40, 0x89, 0xf5, 0x26, - 0x1e, 0x31, 0x64, 0x9e, 0x13, 0xf4, 0x23, 0xeb, 0x2c, 0x7e, 0xbf, 0x75, 0xc6, 0x77, 0xb9, 0x34, - 0xb5, 0xcb, 0x11, 0xf2, 0xa7, 0x44, 0xc9, 0x1f, 0x7b, 0x36, 0xc7, 0x35, 0x6d, 0xd7, 0xa4, 0x67, - 0xfc, 0xd5, 0x64, 0x71, 0xd0, 0x67, 0xe9, 0xf4, 0x98, 0x8c, 0x1d, 0xdb, 0x1e, 0x69, 0x02, 0xbc, - 0x56, 0xb8, 0xe9, 0xaa, 0x14, 0xb6, 0x39, 0x86, 0xfd, 0x3c, 0x13, 0x5e, 0xbf, 0x90, 0xe4, 0xff, - 0xc7, 0x6d, 0xb0, 0xfa, 0x0b, 0x9e, 0xf9, 0xc7, 0x39, 0x01, 0x3a, 0x82, 0xb5, 0xe0, 0xfa, 0x6b, - 0x13, 0x0e, 0x0b, 0xfe, 0x81, 0x5e, 0x16, 0x3f, 0x6a, 0x27, 0x71, 0xb1, 0x87, 0x7e, 0x00, 0x57, - 0xa7, 0xa0, 0x2d, 0x70, 0x9d, 0x59, 0x12, 0xe1, 0x9e, 0x88, 0x23, 0x9c, 0xef, 0x39, 0xdc, 0xab, - 0xec, 0xf7, 0xbc, 0x74, 0xbb, 0x2c, 0x99, 0x8c, 0x32, 0x9c, 0xb9, 0x6f, 0xff, 0x19, 0x28, 0xbb, - 0x84, 0xea, 0xa6, 0xa5, 0xc5, 0xd2, 0xf5, 0x55, 0x21, 0x94, 0x45, 0x80, 0x43, 0x78, 0x62, 0x2e, - 0xd3, 0x41, 0xff, 0x0d, 0x4a, 0x48, 0x92, 0xd2, 0x09, 0x99, 0x6f, 0x90, 0xcd, 0x85, 0xba, 0xea, - 0x6f, 0xd3, 0xa1, 0xcb, 0x78, 0x7e, 0xd8, 0x86, 0x82, 0x4b, 0xbc, 0xc9, 0x48, 0x64, 0x6c, 0x95, - 0xed, 0x97, 0x97, 0xe3, 0x48, 0x4c, 0x3a, 0x19, 0x51, 0x2c, 0x8d, 0xd5, 0x87, 0x50, 0x10, 0x12, - 0xb4, 0x02, 0xc5, 0xfb, 0xfb, 0xf7, 0xf6, 0x0f, 0x3e, 0xd8, 0xaf, 0xa5, 0x10, 0x40, 0x61, 0xa7, - 0xd5, 0x6a, 0x1f, 0x76, 0x6b, 0x69, 0xa4, 0x40, 0x7e, 0xa7, 0x79, 0x80, 0xbb, 0xb5, 0x0c, 0x13, - 0xe3, 0xf6, 0x7b, 0xed, 0x56, 0xb7, 0x96, 0x45, 0x6b, 0x50, 0x16, 0x6d, 0xed, 0xee, 0x01, 0x7e, - 0x7f, 0xa7, 0x5b, 0xcb, 0x45, 0x44, 0x47, 0xed, 0xfd, 0x3b, 0x6d, 0x5c, 0xcb, 0xab, 0xaf, 0xb0, - 0x94, 0x30, 0x81, 0x55, 0x85, 0xc9, 0x5f, 0x3a, 0x92, 0xfc, 0xa9, 0xbf, 0xca, 0x40, 0x23, 0x99, - 0x2a, 0xa1, 0xf7, 0xa6, 0x16, 0xbe, 0x7d, 0x01, 0x9e, 0x35, 0xb5, 0x7a, 0xf4, 0x2c, 0x54, 0x5c, - 0x72, 0x4c, 0x68, 0x7f, 0x28, 0xa8, 0x9b, 0x88, 0x98, 0x65, 0x5c, 0x96, 0x52, 0x6e, 0xe4, 0x09, - 0xb5, 0x8f, 0x49, 0x9f, 0x6a, 0x02, 0x8a, 0xc4, 0xa1, 0x53, 0x98, 0x1a, 0x93, 0x1e, 0x09, 0xa1, - 0xfa, 0xd1, 0x85, 0xf6, 0x52, 0x81, 0x3c, 0x6e, 0x77, 0xf1, 0x0f, 0x6b, 0x59, 0x84, 0xa0, 0xc2, - 0x9b, 0xda, 0xd1, 0xfe, 0xce, 0xe1, 0x51, 0xe7, 0x80, 0xed, 0xe5, 0x25, 0xa8, 0xfa, 0x7b, 0xe9, - 0x0b, 0xf3, 0xea, 0x6d, 0xb8, 0x9a, 0xc0, 0xf3, 0x16, 0xe4, 0xbf, 0xea, 0x3f, 0xd3, 0x50, 0x9d, - 0xba, 0x5a, 0x68, 0x1b, 0xf2, 0x22, 0x71, 0x48, 0xfa, 0x88, 0xc2, 0x91, 0x41, 0xde, 0x43, 0xa1, - 0x8a, 0xde, 0x82, 0x12, 0x91, 0x15, 0x9a, 0x79, 0x57, 0x58, 0xa4, 0xc8, 0x7e, 0x0d, 0x47, 0x9a, - 0x06, 0x16, 0xe8, 0x6d, 0x50, 0x02, 0x8c, 0x90, 0xd9, 0xea, 0xd3, 0x73, 0x32, 0x6c, 0x5f, 0x45, - 0xda, 0x87, 0x36, 0xe8, 0x8d, 0x90, 0x26, 0xe6, 0x66, 0xd3, 0x15, 0x69, 0x2e, 0x14, 0xa4, 0xb1, - 0xaf, 0xaf, 0xb6, 0x60, 0x25, 0xb2, 0x1e, 0xf4, 0x14, 0x28, 0x63, 0xfd, 0x54, 0x56, 0xfe, 0x44, - 0xed, 0xa6, 0x34, 0xd6, 0x4f, 0x45, 0xd1, 0xef, 0x2a, 0x14, 0xd9, 0xe0, 0x40, 0xf7, 0x64, 0x95, - 0xa0, 0x30, 0xd6, 0x4f, 0xdf, 0xd5, 0x3d, 0xf5, 0x43, 0xa8, 0xc4, 0xab, 0x5e, 0xec, 0x0c, 0xbb, - 0xf6, 0xc4, 0x32, 0xb8, 0x8f, 0x3c, 0x16, 0x1d, 0xf4, 0x9a, 0x5f, 0x46, 0xc8, 0x24, 0x5c, 0xf6, - 0x07, 0x36, 0x25, 0x91, 0xaa, 0x99, 0xac, 0x27, 0x3c, 0x86, 0x3c, 0x87, 0x2d, 0x06, 0x41, 0xbc, - 0x7e, 0x25, 0x29, 0x32, 0x6b, 0xa3, 0x0f, 0x01, 0x74, 0x4a, 0x5d, 0xb3, 0x37, 0x09, 0x1d, 0x6f, - 0xcc, 0x87, 0xbd, 0x1d, 0x5f, 0xaf, 0x79, 0x4d, 0xe2, 0xdf, 0xe5, 0xd0, 0x34, 0x82, 0x81, 0x11, - 0x87, 0xea, 0x3e, 0x54, 0xe2, 0xb6, 0xd1, 0x4a, 0xf2, 0xea, 0x9c, 0x4a, 0x72, 0x40, 0xc3, 0x02, - 0x12, 0x97, 0x15, 0xb5, 0x4a, 0xde, 0x51, 0x3f, 0x4b, 0x43, 0xa9, 0x7b, 0x2a, 0x2f, 0x44, 0x42, - 0x99, 0x2c, 0x34, 0xcd, 0x44, 0x8b, 0x42, 0xa2, 0xee, 0x96, 0x0d, 0xaa, 0x79, 0xef, 0x04, 0x57, - 0x3e, 0xb7, 0x6c, 0x9a, 0xec, 0x97, 0x35, 0x25, 0xcc, 0xbd, 0x09, 0x4a, 0x70, 0xaa, 0x58, 0xae, - 0xa1, 0x1b, 0x86, 0x4b, 0x3c, 0x4f, 0xae, 0xcd, 0xef, 0xf2, 0xaa, 0xab, 0xfd, 0xa9, 0x2c, 0x3b, - 0x65, 0xb1, 0xe8, 0xa8, 0x06, 0x54, 0xa7, 0x02, 0x1e, 0x7a, 0x13, 0x8a, 0xce, 0xa4, 0xa7, 0xf9, - 0xdb, 0x33, 0x75, 0x79, 0x7c, 0xde, 0x39, 0xe9, 0x8d, 0xcc, 0xfe, 0x3d, 0x72, 0xe6, 0x3f, 0x8c, - 0x33, 0xe9, 0xdd, 0x13, 0xbb, 0x28, 0x66, 0xc9, 0x44, 0x67, 0x39, 0x81, 0x92, 0x7f, 0x28, 0xd0, - 0xff, 0x45, 0xef, 0x89, 0x5f, 0x8b, 0x4f, 0x0c, 0xc2, 0xd2, 0x7d, 0xe4, 0x9a, 0xdc, 0x82, 0x35, - 0xcf, 0x1c, 0x58, 0xc4, 0xd0, 0xc2, 0x6c, 0x87, 0xcf, 0x56, 0xc2, 0x55, 0x31, 0xb0, 0xe7, 0xa7, - 0x3a, 0xea, 0x3f, 0xd2, 0x50, 0xf2, 0x2f, 0x2c, 0x7a, 0x25, 0x72, 0xee, 0x2a, 0x73, 0x4a, 0x42, - 0xbe, 0x62, 0x58, 0x38, 0x8d, 0x3f, 0x6b, 0xe6, 0xe2, 0xcf, 0x9a, 0x54, 0x01, 0xf7, 0x3f, 0x45, - 0xe4, 0x2e, 0xfc, 0x29, 0xe2, 0x25, 0x40, 0xd4, 0xa6, 0xfa, 0x48, 0x3b, 0xb1, 0xa9, 0x69, 0x0d, - 0x34, 0xb1, 0xd9, 0x82, 0x8b, 0xd5, 0xf8, 0xc8, 0x03, 0x3e, 0x70, 0xc8, 0xf7, 0xfd, 0xa7, 0x69, - 0x28, 0x05, 0x51, 0xf5, 0xa2, 0x75, 0xd0, 0x2b, 0x50, 0x90, 0x81, 0x43, 0x14, 0x42, 0x65, 0x2f, - 0x28, 0xc9, 0xe7, 0x22, 0x25, 0xf9, 0x06, 0x94, 0xc6, 0x84, 0xea, 0x1c, 0x9f, 0x45, 0xc2, 0x19, - 0xf4, 0x6f, 0xbd, 0x01, 0x2b, 0x91, 0x92, 0x34, 0xbb, 0x79, 0xfb, 0xed, 0x0f, 0x6a, 0xa9, 0x46, - 0xf1, 0xb3, 0x2f, 0x6e, 0x64, 0xf7, 0xc9, 0xa7, 0xec, 0xcc, 0xe2, 0x76, 0xab, 0xd3, 0x6e, 0xdd, - 0xab, 0xa5, 0x1b, 0x2b, 0x9f, 0x7d, 0x71, 0xa3, 0x88, 0x09, 0xaf, 0x24, 0xdd, 0xea, 0xc0, 0x6a, - 0xf4, 0xad, 0xc4, 0x63, 0x0f, 0x82, 0xca, 0x9d, 0xfb, 0x87, 0x7b, 0xbb, 0xad, 0x9d, 0x6e, 0x5b, - 0x7b, 0x70, 0xd0, 0x6d, 0xd7, 0xd2, 0xe8, 0x2a, 0x5c, 0xda, 0xdb, 0x7d, 0xb7, 0xd3, 0xd5, 0x5a, - 0x7b, 0xbb, 0xed, 0xfd, 0xae, 0xb6, 0xd3, 0xed, 0xee, 0xb4, 0xee, 0xd5, 0x32, 0xdb, 0x7f, 0x05, - 0xa8, 0xee, 0x34, 0x5b, 0xbb, 0x2c, 0x6e, 0x9a, 0x7d, 0x5d, 0x56, 0xea, 0x72, 0x3c, 0xdf, 0x3f, - 0xf7, 0x0b, 0x7b, 0xe3, 0xfc, 0x42, 0x25, 0xba, 0x0b, 0x79, 0x5e, 0x0a, 0x40, 0xe7, 0x7f, 0x72, - 0x6f, 0x2c, 0xa8, 0x5c, 0xb2, 0x87, 0xe1, 0xd7, 0xe3, 0xdc, 0x6f, 0xf0, 0x8d, 0xf3, 0x0b, 0x99, - 0x08, 0x83, 0x12, 0xe6, 0xf2, 0x8b, 0xbf, 0xc9, 0x37, 0x96, 0x28, 0x6e, 0x32, 0x9f, 0x61, 0x42, - 0xb1, 0xf8, 0x1b, 0x75, 0x63, 0x09, 0x00, 0x43, 0x7b, 0x50, 0xf4, 0x73, 0xc0, 0x45, 0x5f, 0xcd, - 0x1b, 0x0b, 0x0b, 0x8f, 0xec, 0x15, 0x88, 0x5c, 0xfd, 0xfc, 0x5f, 0x00, 0x1a, 0x0b, 0xaa, 0xa8, - 0x68, 0x17, 0x0a, 0x92, 0x25, 0x2f, 0xf8, 0x12, 0xde, 0x58, 0x54, 0x48, 0x64, 0x9b, 0x16, 0x16, - 0x41, 0x16, 0xff, 0xd8, 0xd0, 0x58, 0xa2, 0x40, 0x8c, 0xee, 0x03, 0x44, 0x32, 0xf3, 0x25, 0xfe, - 0x58, 0x68, 0x2c, 0x53, 0xf8, 0x45, 0x07, 0x50, 0x0a, 0x12, 0xa5, 0x85, 0xff, 0x0f, 0x34, 0x16, - 0x57, 0x60, 0xd1, 0x43, 0x28, 0xc7, 0x33, 0x84, 0xe5, 0xfe, 0x0a, 0x68, 0x2c, 0x59, 0x5a, 0x65, - 0xfe, 0xe3, 0xe9, 0xc2, 0x72, 0x7f, 0x09, 0x34, 0x96, 0xac, 0xb4, 0xa2, 0x8f, 0x61, 0x6d, 0x96, - 0xce, 0x2f, 0xff, 0xd3, 0x40, 0xe3, 0x02, 0xb5, 0x57, 0x34, 0x06, 0x34, 0x27, 0x0d, 0xb8, 0xc0, - 0x3f, 0x04, 0x8d, 0x8b, 0x94, 0x62, 0x91, 0x01, 0xd5, 0x69, 0x6e, 0xbd, 0xec, 0x3f, 0x05, 0x8d, - 0xa5, 0xcb, 0xb2, 0xcd, 0xf6, 0x97, 0xdf, 0xac, 0xa7, 0xbf, 0xfa, 0x66, 0x3d, 0xfd, 0xe7, 0x6f, - 0xd6, 0xd3, 0x9f, 0x7f, 0xbb, 0x9e, 0xfa, 0xea, 0xdb, 0xf5, 0xd4, 0x1f, 0xbe, 0x5d, 0x4f, 0xfd, - 0xe8, 0xc5, 0x81, 0x49, 0x87, 0x93, 0xde, 0x66, 0xdf, 0x1e, 0x6f, 0x45, 0x7f, 0xa3, 0x9a, 0xf7, - 0x6b, 0x57, 0xaf, 0xc0, 0xc3, 0xe1, 0xab, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x54, 0x3f, 0x72, - 0x96, 0xfa, 0x25, 0x00, 0x00, + // 3097 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, 0x55, 0x0a, 0x97, 0x13, 0x78, 0x1e, 0xa3, 0x49, 0x43, 0xdb, 0x30, + 0x8f, 0x4c, 0x62, 0x68, 0x32, 0xd5, 0x52, 0xc2, 0xe0, 0x8b, 0xba, 0x63, 0x74, 0x0b, 0x80, 0x8e, + 0x35, 0x97, 0xf4, 0x6c, 0xd7, 0xf0, 0x99, 0xc1, 0xf4, 0x26, 0xec, 0x8e, 0x31, 0xd7, 0xc0, 0x65, + 0x2a, 0x4b, 0x9e, 0xfa, 0xcf, 0x34, 0xd4, 0x26, 0x8e, 0x25, 0xda, 0x80, 0xbc, 0x08, 0x3a, 0x92, + 0x7e, 0x1b, 0x71, 0x54, 0x91, 0x67, 0x58, 0xa8, 0xa2, 0x37, 0xa1, 0x44, 0x64, 0xd8, 0x3d, 0xeb, + 0xf8, 0x8b, 0x34, 0x82, 0x1f, 0x98, 0x4b, 0xd3, 0xc0, 0x02, 0xbd, 0x0d, 0xe5, 0x00, 0x5f, 0x64, + 0xa4, 0xfb, 0xd4, 0xb4, 0x79, 0x80, 0x4c, 0xd2, 0x3e, 0xb4, 0x41, 0xaf, 0x85, 0x14, 0x33, 0x37, + 0x1d, 0xea, 0x48, 0x73, 0xa1, 0x20, 0x8d, 0x7d, 0x7d, 0xb5, 0x09, 0x4b, 0x91, 0xf1, 0xa0, 0x27, + 0xa0, 0x3c, 0xd4, 0xfd, 0xac, 0x80, 0xc8, 0x56, 0x95, 0x86, 0xba, 0xc8, 0x09, 0xa0, 0xcb, 0x50, + 0x64, 0x8d, 0xc7, 0xba, 0xc0, 0xb8, 0x2c, 0x2e, 0x0c, 0xf5, 0xf1, 0xbb, 0xba, 0xa7, 0xbe, 0x0f, + 0xd5, 0x78, 0x9e, 0x8f, 0xed, 0x7f, 0xd7, 0x1e, 0x59, 0x06, 0xf7, 0x91, 0xc7, 0xa2, 0x82, 0x5e, + 0x81, 0xfc, 0x89, 0x2d, 0x20, 0x72, 0xf6, 0x1a, 0x3d, 0xb0, 0x29, 0x89, 0xe4, 0x42, 0x84, 0xb6, + 0x6a, 0x02, 0x9a, 0x4e, 0x97, 0x24, 0x74, 0xf1, 0x56, 0xbc, 0x8b, 0xa7, 0x12, 0x13, 0x2f, 0xb3, + 0xbb, 0xfa, 0x04, 0xf2, 0x1c, 0x5d, 0x19, 0x52, 0xf2, 0xe4, 0xa0, 0x64, 0xf2, 0xac, 0x8c, 0xde, + 0x07, 0xd0, 0x29, 0x75, 0xcd, 0xc3, 0x51, 0xd8, 0xc1, 0xda, 0x6c, 0x74, 0xde, 0xf4, 0xf5, 0xb6, + 0xae, 0x48, 0x98, 0xbe, 0x18, 0x9a, 0x46, 0xa0, 0x3a, 0xe2, 0x50, 0xdd, 0x85, 0x6a, 0xdc, 0x36, + 0x9a, 0xa6, 0x5f, 0x9e, 0x91, 0xa6, 0x0f, 0xd8, 0x62, 0xc0, 0x35, 0xb3, 0x22, 0x11, 0xcc, 0x2b, + 0xea, 0xa7, 0x69, 0x28, 0xb1, 0x4d, 0xcf, 0xcf, 0x6d, 0x42, 0x0e, 0x32, 0x34, 0xcd, 0x44, 0x33, + 0x6e, 0x22, 0xa9, 0x99, 0x0d, 0x52, 0xa5, 0xef, 0x04, 0xc8, 0x94, 0x5b, 0x34, 0x9a, 0xf7, 0xd3, + 0x65, 0x12, 0x8d, 0x7f, 0x29, 0x3f, 0x86, 0x9d, 0x3b, 0xf4, 0x3a, 0x14, 0xf4, 0x5e, 0x90, 0x4c, + 0xaa, 0xce, 0x70, 0xe7, 0xab, 0xae, 0x77, 0xc7, 0x9b, 0x5c, 0x13, 0x4b, 0x0b, 0xf9, 0x69, 0x99, + 0x20, 0xdf, 0xfa, 0x36, 0xf3, 0x2b, 0x74, 0xe2, 0xe0, 0x54, 0x05, 0x38, 0xd8, 0xbd, 0xdf, 0xd9, + 0xde, 0xb9, 0xbd, 0xd3, 0xda, 0x96, 0x00, 0xb5, 0xbd, 0xdd, 0xda, 0x56, 0x32, 0x4c, 0x0f, 0xb7, + 0xee, 0x77, 0x1e, 0xb4, 0xb6, 0x95, 0xac, 0xfa, 0x06, 0x94, 0x83, 0xa3, 0xc5, 0x82, 0x35, 0xdd, + 0x30, 0x5c, 0xe2, 0x79, 0x72, 0xd6, 0xfd, 0x2a, 0x4f, 0xb6, 0xdb, 0x1f, 0xcb, 0x6c, 0x63, 0x16, + 0x8b, 0x8a, 0x6a, 0x40, 0x6d, 0x82, 0x31, 0xa0, 0x37, 0xa0, 0xe8, 0x8c, 0x0e, 0x35, 0x7f, 0xe1, + 0x26, 0x10, 0xc4, 0x27, 0xee, 0xa3, 0xc3, 0x81, 0xd9, 0xbb, 0x4b, 0x4e, 0xfd, 0x69, 0x72, 0x46, + 0x87, 0x77, 0xc5, 0xfa, 0x8a, 0x5e, 0x32, 0xd1, 0x5e, 0x7e, 0x9a, 0x86, 0x92, 0xbf, 0x5f, 0xd1, + 0xff, 0x44, 0xd1, 0xc2, 0xff, 0x07, 0x93, 0x48, 0x63, 0xa4, 0xff, 0x08, 0x58, 0xdc, 0x80, 0x15, + 0xcf, 0x3c, 0xb6, 0x88, 0xa1, 0x85, 0xf1, 0x22, 0xef, 0xae, 0x84, 0x6b, 0xa2, 0xe1, 0x9e, 0x1f, + 0x2c, 0xde, 0xc9, 0x95, 0xb2, 0x4a, 0xee, 0x4e, 0xae, 0x94, 0x53, 0xf2, 0xea, 0xaf, 0xd3, 0xa0, + 0x4c, 0x1e, 0x9e, 0x7f, 0xe7, 0xc7, 0xb0, 0xbb, 0x8a, 0x1d, 0x52, 0x8d, 0xb0, 0x8f, 0x08, 0x22, + 0xe6, 0x65, 0x5c, 0x61, 0xd2, 0x96, 0x2f, 0x54, 0xff, 0x91, 0x86, 0x92, 0x0f, 0xb5, 0xe8, 0xa5, + 0xc8, 0x31, 0xae, 0xce, 0x48, 0x04, 0xfa, 0x8a, 0x61, 0x92, 0x3f, 0x3e, 0xa4, 0xcc, 0xf9, 0x87, + 0x94, 0xf4, 0xb7, 0xc6, 0xff, 0x6d, 0x96, 0x3b, 0xf7, 0x6f, 0xb3, 0x17, 0x00, 0x51, 0x9b, 0xea, + 0x03, 0xed, 0xc4, 0xa6, 0xa6, 0x75, 0xac, 0x89, 0x1d, 0x22, 0x18, 0xb8, 0xc2, 0x5b, 0x1e, 0xf0, + 0x86, 0xbd, 0x60, 0xb3, 0x04, 0x5c, 0xea, 0xbc, 0x39, 0xfb, 0x4b, 0x50, 0x90, 0x74, 0x41, 0x24, + 0xed, 0x65, 0x2d, 0xc8, 0x9c, 0xe7, 0x22, 0x99, 0xf3, 0x06, 0x94, 0x86, 0x84, 0xea, 0x9c, 0x50, + 0x8a, 0x34, 0x43, 0x50, 0xbf, 0xf1, 0x1a, 0x2c, 0x45, 0x7e, 0x9f, 0x30, 0x20, 0xdb, 0x6d, 0xbd, + 0xa7, 0xa4, 0x1a, 0xc5, 0x4f, 0x3f, 0xbf, 0x9a, 0xdd, 0x25, 0x1f, 0xb3, 0x83, 0x86, 0x5b, 0xcd, + 0x76, 0xab, 0x79, 0x57, 0x49, 0x37, 0x96, 0x3e, 0xfd, 0xfc, 0x6a, 0x11, 0x13, 0x9e, 0x3f, 0xbc, + 0xd1, 0x86, 0xe5, 0xe8, 0xaa, 0xc4, 0x0f, 0x35, 0x82, 0xea, 0xf6, 0xc1, 0xde, 0xbd, 0x9d, 0xe6, + 0x66, 0xb7, 0xa5, 0x3d, 0xe8, 0x74, 0x5b, 0x4a, 0x1a, 0x5d, 0x86, 0x0b, 0xf7, 0x76, 0xde, 0x6d, + 0x77, 0xb5, 0xe6, 0xbd, 0x9d, 0xd6, 0x6e, 0x57, 0xdb, 0xec, 0x76, 0x37, 0x9b, 0x77, 0x95, 0xcc, + 0xc6, 0x5f, 0x01, 0x6a, 0x9b, 0x5b, 0xcd, 0x1d, 0xc6, 0x96, 0xcc, 0x9e, 0x2e, 0xf3, 0xb3, 0x39, + 0x9e, 0xe5, 0x39, 0xf3, 0x35, 0x48, 0xe3, 0xec, 0xf4, 0x34, 0xba, 0x0d, 0x79, 0x9e, 0x00, 0x42, + 0x67, 0x3f, 0x0f, 0x69, 0xcc, 0xc9, 0x57, 0xb3, 0x8f, 0xe1, 0xa7, 0xe8, 0xcc, 0xf7, 0x22, 0x8d, + 0xb3, 0xd3, 0xd7, 0x08, 0x43, 0x39, 0xcc, 0xe0, 0xcc, 0x7f, 0x3f, 0xd2, 0x58, 0x20, 0xa5, 0xcd, + 0x7c, 0x86, 0x61, 0xe4, 0xfc, 0xf7, 0x14, 0x8d, 0x05, 0xee, 0x03, 0x74, 0x0f, 0x8a, 0x7e, 0xe4, + 0x3f, 0xef, 0x85, 0x47, 0x63, 0x6e, 0xba, 0x99, 0x2d, 0x81, 0xc8, 0xd0, 0x9c, 0xfd, 0x5c, 0xa5, + 0x31, 0x27, 0x77, 0x8e, 0x76, 0xa0, 0x20, 0x63, 0xa3, 0x39, 0xaf, 0x36, 0x1a, 0xf3, 0xd2, 0xc7, + 0x6c, 0xd2, 0xc2, 0xd4, 0xd7, 0xfc, 0x47, 0x38, 0x8d, 0x05, 0x7e, 0x0b, 0xa0, 0x03, 0x80, 0x48, + 0x3e, 0x66, 0x81, 0xd7, 0x35, 0x8d, 0x45, 0xd2, 0xfd, 0xa8, 0x03, 0xa5, 0x20, 0x3c, 0x9e, 0xfb, + 0xd6, 0xa5, 0x31, 0x3f, 0xef, 0x8e, 0x1e, 0x42, 0x25, 0x1e, 0x17, 0x2e, 0xf6, 0x82, 0xa5, 0xb1, + 0x60, 0x42, 0x9d, 0xf9, 0x8f, 0x07, 0x89, 0x8b, 0xbd, 0x68, 0x69, 0x2c, 0x98, 0x5f, 0x47, 0x1f, + 0xc2, 0xca, 0x74, 0x10, 0xb7, 0xf8, 0x03, 0x97, 0xc6, 0x39, 0x32, 0xee, 0x68, 0x08, 0x68, 0x46, + 0xf0, 0x77, 0x8e, 0xf7, 0x2e, 0x8d, 0xf3, 0x24, 0xe0, 0x91, 0x01, 0xb5, 0xc9, 0x88, 0x6a, 0xd1, + 0xf7, 0x2f, 0x8d, 0x85, 0x93, 0xf1, 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, + 0xc9, 0xdf, 0xac, 0x67, 0x88, 0x87, 0x05, 0x7e, 0x1d, 0xbe, 0xfc, 0xaf, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xf8, 0x2c, 0x9d, 0xd4, 0xa6, 0x28, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -5142,10 +5382,15 @@ func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - if len(m.Votes) > 0 { - for iNdEx := len(m.Votes) - 1; iNdEx >= 0; iNdEx-- { + if m.MaxTxBytes != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.MaxTxBytes)) + i-- + dAtA[i] = 0x30 + } + if len(m.ByzantineValidators) > 0 { + for iNdEx := len(m.ByzantineValidators) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Votes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.ByzantineValidators[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -5153,22 +5398,44 @@ func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- + 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 } } - if m.BlockDataSize != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.BlockDataSize)) - i-- - dAtA[i] = 0x10 - } - 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]))) - i-- - dAtA[i] = 0xa + { + 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 } @@ -6325,20 +6592,20 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err } } if len(m.RefetchChunks) > 0 { - dAtA43 := make([]byte, len(m.RefetchChunks)*10) - var j42 int + dAtA45 := make([]byte, len(m.RefetchChunks)*10) + var j44 int for _, num := range m.RefetchChunks { for num >= 1<<7 { - dAtA43[j42] = uint8(uint64(num)&0x7f | 0x80) + dAtA45[j44] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j42++ + j44++ } - dAtA43[j42] = uint8(num) - j42++ + dAtA45[j44] = uint8(num) + j44++ } - i -= j42 - copy(dAtA[i:], dAtA43[:j42]) - i = encodeVarintTypes(dAtA, i, uint64(j42)) + i -= j44 + copy(dAtA[i:], dAtA45[:j44]) + i = encodeVarintTypes(dAtA, i, uint64(j44)) i-- dAtA[i] = 0x12 } @@ -6370,15 +6637,30 @@ 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 + dAtA[i] = 0x12 } } + if m.ModifiedTx { + i-- + if m.ModifiedTx { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -6528,6 +6810,48 @@ func (m *LastCommitInfo) 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) @@ -6669,6 +6993,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) @@ -6785,6 +7144,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) @@ -6810,12 +7219,12 @@ func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n51, err51 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err51 != nil { - return 0, err51 + 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 -= n51 - i = encodeVarintTypes(dAtA, i, uint64(n51)) + i -= n54 + i = encodeVarintTypes(dAtA, i, uint64(n54)) i-- dAtA[i] = 0x22 if m.Height != 0 { @@ -7364,21 +7773,29 @@ 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)) - } - if len(m.Votes) > 0 { - for _, e := range m.Votes { + 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 } @@ -7963,9 +8380,12 @@ func (m *ResponsePrepareProposal) Size() (n int) { } var l int _ = l - if len(m.BlockData) > 0 { - for _, b := range m.BlockData { - l = len(b) + if m.ModifiedTx { + n += 2 + } + if len(m.TxRecords) > 0 { + for _, e := range m.TxRecords { + l = e.Size() n += 1 + l + sovTypes(uint64(l)) } } @@ -8030,6 +8450,24 @@ func (m *LastCommitInfo) 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 @@ -8090,6 +8528,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 @@ -8134,6 +8588,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 @@ -10490,7 +10962,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 { @@ -10517,31 +10989,14 @@ 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) - } - m.BlockDataSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.BlockDataSize |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Votes", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Header", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -10568,11 +11023,128 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Votes = append(m.Votes, &types1.Vote{}) - if err := m.Votes[len(m.Votes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + 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 + } + } default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -13643,10 +14215,10 @@ 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) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ModifiedTx", wireType) } - var byteLen int + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -13656,23 +14228,45 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + m.ModifiedTx = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxRecords", 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 + 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 @@ -14080,6 +14674,109 @@ func (m *LastCommitInfo) 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 @@ -14489,6 +15186,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 @@ -14797,6 +15597,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/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 a88b499f4..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,10 +16,11 @@ 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" + 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" @@ -52,6 +54,7 @@ type BlockchainReactorPair struct { } func newBlockchainReactor( + t *testing.T, logger log.Logger, genDoc *types.GenesisDoc, privVals []types.PrivValidator, @@ -78,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. @@ -85,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) } @@ -112,9 +127,10 @@ func newBlockchainReactor( 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) @@ -140,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) @@ -202,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() @@ -213,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) @@ -254,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 { @@ -278,21 +294,6 @@ func TestBadBlockStopsPeer(t *testing.T) { assert.True(t, lastReactorPair.reactor.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/v1/reactor.go b/blockchain/v1/reactor.go index 95e165c45..4b12f70e9 100644 --- a/blockchain/v1/reactor.go +++ b/blockchain/v1/reactor.go @@ -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/reactor_test.go b/blockchain/v2/reactor_test.go index 808b16050..f5ca11421 100644 --- a/blockchain/v2/reactor_test.go +++ b/blockchain/v2/reactor_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" @@ -19,12 +20,13 @@ import ( 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" "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" @@ -142,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 @@ -151,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) @@ -160,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) } @@ -391,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() @@ -434,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, @@ -445,21 +459,6 @@ func TestReactorSetSwitchNil(t *testing.T) { assert.Nil(t, reactor.io) } -//---------------------------------------------- -// 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 } @@ -488,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) { @@ -510,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) } @@ -539,9 +551,11 @@ func newReactorStore( lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) } - thisBlock := makeBlock(blockHeight, state, lastCommit) + thisBlock := sf.MakeBlock(state, blockHeight, lastCommit) + + thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) - thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes) blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()} state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock) diff --git a/consensus/byzantine_test.go b/consensus/byzantine_test.go index 1f14b11aa..594c7d9a2 100644 --- a/consensus/byzantine_test.go +++ b/consensus/byzantine_test.go @@ -187,7 +187,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { } var commit *types.Commit - var votes []*types.Vote switch { case lazyProposer.Height == lazyProposer.state.InitialHeight: // We're creating a proposal for the first block. @@ -196,7 +195,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { case lazyProposer.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = lazyProposer.LastCommit.MakeCommit() - votes = lazyProposer.LastCommit.GetVotes() default: // This shouldn't happen. lazyProposer.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block") return @@ -213,9 +211,11 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { } proposerAddr := lazyProposer.privValidatorPubKey.Address() - block, blockParts := lazyProposer.blockExec.CreateProposalBlock( - lazyProposer.Height, lazyProposer.state, commit, proposerAddr, votes, - ) + 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. @@ -463,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() @@ -477,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 a0cdae1df..183fedefd 100644 --- a/consensus/mempool_test.go +++ b/consensus/mempool_test.go @@ -259,5 +259,5 @@ func (app *CounterApplication) Commit() abci.ResponseCommit { func (app *CounterApplication) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{BlockData: req.BlockData} + return abci.ResponsePrepareProposal{} } diff --git a/consensus/replay_test.go b/consensus/replay_test.go index a081e262e..61bc5f438 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -31,6 +31,7 @@ import ( 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/types" ) @@ -362,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) @@ -392,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) @@ -429,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]) @@ -504,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]) @@ -665,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) @@ -690,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) @@ -699,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 @@ -715,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 @@ -775,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 { @@ -809,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)) @@ -829,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, @@ -859,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)) } @@ -890,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 := 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 @@ -947,52 +959,6 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) { } } -func makeBlocks(n int, state *sm.State, privVal types.PrivValidator) []*types.Block { - blocks := make([]*types.Block, 0) - - var ( - prevBlock *types.Block - prevBlockMeta *types.BlockMeta - ) - - appHeight := byte(0x01) - for i := 0; i < n; i++ { - height := int64(i + 1) - - block, parts := makeBlock(*state, prevBlock, prevBlockMeta, privVal, height) - blocks = append(blocks, block) - - prevBlock = block - prevBlockMeta = types.NewBlockMeta(block, parts) - - // update state - state.AppHash = []byte{appHeight} - appHeight++ - state.LastBlockHeight = height - } - - return blocks -} - -func makeBlock(state sm.State, lastBlock *types.Block, lastBlockMeta *types.BlockMeta, - privVal types.PrivValidator, height int64) (*types.Block, *types.PartSet) { - - lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil) - if height > 1 { - vote, _ := types.MakeVote( - lastBlock.Header.Height, - lastBlockMeta.BlockID, - state.Validators, - privVal, - lastBlock.Header.ChainID, - time.Now()) - lastCommit = types.NewCommit(vote.Height, vote.Round, - lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) - } - - return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) -} - type badApp struct { abci.BaseApplication numBlocks byte @@ -1144,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 } @@ -1167,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)) } @@ -1184,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, } } @@ -1224,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 d2f3d2b42..8e662ea45 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -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,13 +1196,12 @@ 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 - var votes []*types.Vote switch { case cs.Height == cs.state.InitialHeight: // We're creating a proposal for the first block. @@ -1203,23 +1211,20 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa case cs.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = cs.LastCommit.MakeCommit() - votes = cs.LastCommit.GetVotes() 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, votes) + return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) } // Enter: `timeoutPropose` after entering Propose. 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/evidence/mocks/block_store.go b/evidence/mocks/block_store.go index 02a90f831..5a16afc2a 100644 --- a/evidence/mocks/block_store.go +++ b/evidence/mocks/block_store.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - types "github.com/tendermint/tendermint/types" ) diff --git a/evidence/pool_test.go b/evidence/pool_test.go index 365a3be88..c5939d43e 100644 --- a/evidence/pool_test.go +++ b/evidence/pool_test.go @@ -18,6 +18,7 @@ import ( tmversion "github.com/tendermint/tendermint/proto/tendermint/version" sm "github.com/tendermint/tendermint/state" smmocks "github.com/tendermint/tendermint/state/mocks" + sf "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/store" "github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/version" @@ -147,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) @@ -181,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) @@ -214,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) @@ -226,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}) @@ -306,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) @@ -398,23 +400,26 @@ 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++ { lastCommit := makeCommit(i-1, valAddr) - block, _ := state.MakeBlock(i, []types.Tx{}, lastCommit, nil, - state.Validators.GetProposer().Address) + block := sf.MakeBlock(state, i, lastCommit) + 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 +432,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/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/node/node_test.go b/node/node_test.go index 5e65ad2b4..5382c94df 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -305,15 +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()) @@ -384,19 +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/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index f7c5e2412..9b74a397f 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -126,15 +126,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; - // votes includes all votes from the previous block. This contains vote extension data that can be used in proposal - // preparation. The votes here will then form the last commit that gets sent in the proposed block. - repeated types.Vote votes = 3; + 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; } //---------------------------------------- @@ -298,7 +298,8 @@ message ResponseApplySnapshotChunk { } message ResponsePrepareProposal { - repeated bytes block_data = 1; + bool modified_tx = 1; + repeated TxRecord tx_records = 2; } //---------------------------------------- @@ -326,6 +327,11 @@ message LastCommitInfo { 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. @@ -354,6 +360,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 @@ -374,6 +393,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/mocks/app_conn_consensus.go b/proxy/mocks/app_conn_consensus.go index 0cec96536..324e4b199 100644 --- a/proxy/mocks/app_conn_consensus.go +++ b/proxy/mocks/app_conn_consensus.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - abcicli "github.com/tendermint/tendermint/abci/client" types "github.com/tendermint/tendermint/abci/types" diff --git a/proxy/mocks/app_conn_mempool.go b/proxy/mocks/app_conn_mempool.go index 3e4bd93a0..e33bc4b3a 100644 --- a/proxy/mocks/app_conn_mempool.go +++ b/proxy/mocks/app_conn_mempool.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - abcicli "github.com/tendermint/tendermint/abci/client" types "github.com/tendermint/tendermint/abci/types" 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/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/state/execution.go b/state/execution.go index 2e7b4b254..0659bbf61 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,10 +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, votes []*types.Vote, -) (*types.Block, *types.PartSet) { +) (*types.Block, error) { maxBytes := state.ConsensusParams.Block.MaxBytes maxGas := state.ConsensusParams.Block.MaxGas @@ -109,12 +110,17 @@ 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( + localLastCommit := getBeginBlockValidatorInfo(block, blockExec.store, state.InitialHeight) + rpp, err := blockExec.proxyApp.PrepareProposalSync( abci.RequestPrepareProposal{ - BlockData: txs.ToSliceOfBytes(), - BlockDataSize: maxDataBytes, - Votes: types.VotesToProto(votes), + 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 { @@ -128,19 +134,28 @@ func (blockExec *BlockExecutor) CreateProposalBlock( // purpose for now. panic(err) } - newTxs := preparedProposal.GetBlockData() - var txSize int - for _, tx := range newTxs { - txSize += len(tx) - if maxDataBytes < int64(txSize) { - panic("block data exceeds max amount of allowed bytes") - } + if !rpp.ModifiedTx { + return block, nil + } + txrSet := types.NewTxRecordSet(rpp.TxRecords) + + if err := txrSet.Validate(maxDataBytes, block.Txs); err != nil { + return nil, err } - modifiedTxs := types.ToTxs(preparedProposal.GetBlockData()) - - return state.MakeBlock(height, modifiedTxs, commit, evidence, proposerAddr) + 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()) + } + } + for _, atx := range txrSet.AddedTxs() { + if err := blockExec.mempool.CheckTx(atx, nil, mempool.TxInfo{}); err != nil { + blockExec.logger.Error("error adding tx to the mempool", "error", err, "tx hash", atx.Hash()) + } + } + itxs := txrSet.IncludedTxs() + return state.MakeBlock(height, itxs, commit, evidence, proposerAddr), nil } // ValidateBlock validates the given block against the given state. @@ -407,6 +422,24 @@ func getBeginBlockValidatorInfo(block *types.Block, store Store, } } +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 a8aeffe93..5cfea42d5 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -10,17 +10,20 @@ import ( "github.com/stretchr/testify/require" 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" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/state/mocks" + sf "github.com/tendermint/tendermint/state/test/factory" + "github.com/tendermint/tendermint/test/factory" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" "github.com/tendermint/tendermint/version" @@ -29,7 +32,6 @@ import ( var ( chainID = "execution_chain" testPartSize uint32 = 65536 - nTxsPerBlock = 10 ) func TestApplyBlock(t *testing.T) { @@ -42,12 +44,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 := makeBlock(state, 1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, 1, new(types.Commit)) + 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) @@ -100,7 +114,7 @@ func TestBeginBlockValidators(t *testing.T) { lastCommit := types.NewCommit(1, 0, prevBlockID, tc.lastCommitSigs) // block for height 2 - block, _ := state.MakeBlock(2, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address) + block := sf.MakeBlock(state, 2, lastCommit) _, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateStore, 1) require.Nil(t, err, tc.desc) @@ -197,14 +211,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 := makeBlock(state, 1) + 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) @@ -355,12 +383,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{}, ) @@ -378,8 +418,10 @@ func TestEndBlockValidatorUpdates(t *testing.T) { ) require.NoError(t, err) - block := makeBlock(state, 1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, 1, new(types.Commit)) + 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) @@ -430,12 +472,14 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { stateStore, log.TestingLogger(), proxyApp.Consensus(), - mmock.Mempool{}, + new(mpmocks.Mempool), sm.EmptyEvidencePool{}, ) - block := makeBlock(state, 1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, 1, new(types.Commit)) + 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) @@ -449,6 +493,201 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { assert.NotEmpty(t, state.NextValidators.Validators) } +func TestEmptyPrepareProposal(t *testing.T) { + const height = 2 + + app := &testApp{} + 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) +} + +// 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.MakeTenTxs(height) + 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{ + ModifiedTx: true, + TxRecords: trs, + }, nil) + 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. The test also +// ensures that any transactions added are also checked into the mempool. +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.MakeTenTxs(height) + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs[2:])) + mp.On("CheckTx", mock.Anything, mock.Anything, mock.Anything).Return(nil).Twice() + + 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{ + ModifiedTx: true, + TxRecords: trs, + }, nil) + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + + 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) + mp.AssertCalled(t, "CheckTx", types.Tx(trs[0].Tx), mock.Anything, mock.Anything) + mp.AssertCalled(t, "CheckTx", types.Tx(trs[1].Tx), mock.Anything, mock.Anything) +} + +// 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.MakeTenTxs(height) + 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{ + ModifiedTx: true, + TxRecords: trs, + }, nil) + + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + + 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) + +} + func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.BlockID { var ( h = make([]byte, tmhash.Size) @@ -464,3 +703,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 19549f160..8a7311ed9 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,11 +11,12 @@ 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" sm "github.com/tendermint/tendermint/state" + sf "github.com/tendermint/tendermint/state/test/factory" + "github.com/tendermint/tendermint/test/factory" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" ) @@ -54,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, makeTxs(height), lastCommit, evidence, proposerAddr) + block := state.MakeBlock(height, factory.MakeTenTxs(height), 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 } @@ -85,14 +92,6 @@ func makeValidCommit( return types.NewCommit(height, 0, blockID, sigs), nil } -// make some bogus txs -func makeTxs(height int64) (txs []types.Tx) { - for i := 0; i < nTxsPerBlock; i++ { - txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) - } - return txs -} - func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) { vals := make([]types.GenesisValidator, nVals) privVals := make(map[string]types.PrivValidator, nVals) @@ -131,17 +130,6 @@ func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValida return s, stateDB, privVals } -func makeBlock(state sm.State, height int64) *types.Block { - block, _ := state.MakeBlock( - height, - makeTxs(state.LastBlockHeight), - new(types.Commit), - nil, - state.Validators.GetProposer().Address, - ) - return block -} - func genValSet(size int) *types.ValidatorSet { vals := make([]*types.Validator, size) for i := 0; i < size; i++ { @@ -151,11 +139,12 @@ func genValSet(size int) *types.ValidatorSet { } func makeHeaderPartsResponsesValPubKeyChange( + t *testing.T, state sm.State, pubkey crypto.PubKey, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { - block := makeBlock(state, state.LastBlockHeight+1) + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, @@ -175,11 +164,13 @@ func makeHeaderPartsResponsesValPubKeyChange( } func makeHeaderPartsResponsesValPowerChange( + t *testing.T, state sm.State, power int64, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { - block := makeBlock(state, state.LastBlockHeight+1) + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) + abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, @@ -199,11 +190,12 @@ func makeHeaderPartsResponsesValPowerChange( } func makeHeaderPartsResponsesParams( + t *testing.T, state sm.State, params tmproto.ConsensusParams, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { - block := makeBlock(state, state.LastBlockHeight+1) + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(¶ms)}, diff --git a/state/mocks/evidence_pool.go b/state/mocks/evidence_pool.go index e4f9c7370..6f41e120f 100644 --- a/state/mocks/evidence_pool.go +++ b/state/mocks/evidence_pool.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/state" types "github.com/tendermint/tendermint/types" diff --git a/state/mocks/store.go b/state/mocks/store.go index 722c48a6f..4308d4ead 100644 --- a/state/mocks/store.go +++ b/state/mocks/store.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/state" tendermintstate "github.com/tendermint/tendermint/proto/tendermint/state" 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 3f27efe42..e943c37a0 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -21,6 +21,7 @@ import ( tmstate "github.com/tendermint/tendermint/proto/tendermint/state" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" sm "github.com/tendermint/tendermint/state" + sf "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/types" ) @@ -101,7 +102,7 @@ func TestABCIResponsesSaveLoad1(t *testing.T) { state.LastBlockHeight++ // Build mock responses. - block := makeBlock(state, 2) + block := sf.MakeBlock(state, 2, new(types.Commit)) abciResponses := new(tmstate.ABCIResponses) dtxs := make([]*abci.ResponseDeliverTx, 2) @@ -269,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) } @@ -443,8 +444,10 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { // NewValidatorSet calls IncrementProposerPriority but uses on a copy of val1 assert.EqualValues(t, 0, val1.ProposerPriority) - block := makeBlock(state, state.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) + 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}, @@ -557,8 +560,10 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { // we only have one validator: assert.Equal(t, val1PubKey.Address(), state.Validators.Proposer.Address) - block := makeBlock(state, state.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) + 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{}, @@ -744,8 +749,10 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) - block := makeBlock(oldState, oldState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) + 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) @@ -773,8 +780,12 @@ func TestLargeGenesisValidator(t *testing.T) { BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}}, } - block := makeBlock(oldState, oldState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) + + 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) @@ -788,8 +799,12 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) - block := makeBlock(lastState, lastState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(lastState, lastState.LastBlockHeight+1, new(types.Commit)) + + 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) @@ -821,8 +836,11 @@ func TestLargeGenesisValidator(t *testing.T) { BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}}, } - block := makeBlock(oldState, oldState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) + 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) } @@ -836,8 +854,14 @@ func TestLargeGenesisValidator(t *testing.T) { BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}}, } - block = makeBlock(oldState, oldState.LastBlockHeight+1) - blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + + block = sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) + 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) @@ -857,8 +881,12 @@ func TestLargeGenesisValidator(t *testing.T) { } validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) - block = makeBlock(curState, curState.LastBlockHeight+1) - blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block = sf.MakeBlock(curState, curState.LastBlockHeight+1, new(types.Commit)) + + 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) { @@ -882,8 +910,12 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) - block := makeBlock(updatedState, updatedState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(updatedState, updatedState.LastBlockHeight+1, new(types.Commit)) + + 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) @@ -938,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 @@ -977,7 +1009,7 @@ func TestStateMakeBlock(t *testing.T) { proposerAddress := state.Validators.GetProposer().Address stateVersion := state.Version.Consensus - block := makeBlock(state, 2) + block := sf.MakeBlock(state, 2, new(types.Commit)) // test we set some fields assert.Equal(t, stateVersion, block.Version) @@ -1019,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 new file mode 100644 index 000000000..35e46787c --- /dev/null +++ b/state/test/factory/block.go @@ -0,0 +1,75 @@ +package factory + +import ( + "time" + + sm "github.com/tendermint/tendermint/state" + "github.com/tendermint/tendermint/test/factory" + "github.com/tendermint/tendermint/types" +) + +func MakeBlocks(n int, state *sm.State, privVal types.PrivValidator) ([]*types.Block, error) { + blocks := make([]*types.Block, n) + + var ( + prevBlock *types.Block + prevBlockMeta *types.BlockMeta + ) + + appHeight := byte(0x01) + for i := 0; i < n; i++ { + height := int64(i + 1) + + 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) + + // update state + state.AppHash = []byte{appHeight} + appHeight++ + state.LastBlockHeight = height + } + + return blocks, nil +} + +func MakeBlock(state sm.State, height int64, c *types.Commit) *types.Block { + return state.MakeBlock( + height, + factory.MakeTenTxs(state.LastBlockHeight), + c, + nil, + state.Validators.GetProposer().Address, + ) +} + +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( + lastBlock.Header.Height, + lastBlockMeta.BlockID, + state.Validators, + privVal, + lastBlock.Header.ChainID, + time.Now()) + lastCommit = types.NewCommit(vote.Height, vote.Round, + lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) + } + + 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 afd47a650..f4de55f80 100644 --- a/state/validation_test.go +++ b/state/validation_test.go @@ -12,10 +12,12 @@ 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" + sf "github.com/tendermint/tendermint/state/test/factory" + "github.com/tendermint/tendermint/test/factory" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" ) @@ -29,11 +31,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) @@ -73,12 +87,11 @@ func TestValidateBlockHeader(t *testing.T) { // Build up state for multiple heights for height := int64(1); height < validationTestsStopHeight; height++ { - proposerAddr := state.Validators.GetProposer().Address /* Invalid blocks don't pass */ for _, tc := range testCases { - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, proposerAddr) + block := sf.MakeBlock(state, height, lastCommit) tc.malleateBlock(block) err := blockExec.ValidateBlock(state, block) require.Error(t, err, tc.name) @@ -88,7 +101,8 @@ func TestValidateBlockHeader(t *testing.T) { A good block passes */ var err error - state, _, lastCommit, err = makeAndCommitGoodBlock(state, height, lastCommit, proposerAddr, blockExec, privVals, nil) + state, _, lastCommit, err = makeAndCommitGoodBlock( + state, height, lastCommit, state.Validators.GetProposer().Address, blockExec, privVals, nil) require.NoError(t, err, "height %d", height) } } @@ -100,11 +114,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) @@ -133,7 +159,7 @@ func TestValidateBlockCommit(t *testing.T) { state.LastBlockID, []types.CommitSig{wrongHeightVote.CommitSig()}, ) - block, _ := state.MakeBlock(height, makeTxs(height), wrongHeightCommit, nil, proposerAddr) + block := sf.MakeBlock(state, height, wrongHeightCommit) err = blockExec.ValidateBlock(state, block) _, isErrInvalidCommitHeight := err.(types.ErrInvalidCommitHeight) require.True(t, isErrInvalidCommitHeight, "expected ErrInvalidCommitHeight at height %d but got: %v", height, err) @@ -141,7 +167,7 @@ func TestValidateBlockCommit(t *testing.T) { /* #2589: test len(block.LastCommit.Signatures) == state.LastValidators.Size() */ - block, _ = state.MakeBlock(height, makeTxs(height), wrongSigsCommit, nil, proposerAddr) + block = sf.MakeBlock(state, height, wrongSigsCommit) err = blockExec.ValidateBlock(state, block) _, isErrInvalidCommitSignatures := err.(types.ErrInvalidCommitSignatures) require.True(t, isErrInvalidCommitSignatures, @@ -222,12 +248,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) @@ -248,7 +285,8 @@ func TestValidateBlockEvidence(t *testing.T) { evidence = append(evidence, newEv) currentBytes += int64(len(newEv.Bytes())) } - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, evidence, proposerAddr) + block := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + err := blockExec.ValidateBlock(state, block) if assert.Error(t, err) { _, ok := err.(*types.ErrEvidenceOverflow) diff --git a/statesync/mocks/state_provider.go b/statesync/mocks/state_provider.go index fdd890422..7ff78561f 100644 --- a/statesync/mocks/state_provider.go +++ b/statesync/mocks/state_provider.go @@ -6,7 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/state" types "github.com/tendermint/tendermint/types" diff --git a/store/store_test.go b/store/store_test.go index ea07c73e6..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" @@ -21,6 +22,7 @@ import ( tmstore "github.com/tendermint/tendermint/proto/tendermint/store" tmversion "github.com/tendermint/tendermint/proto/tendermint/version" sm "github.com/tendermint/tendermint/state" + "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" "github.com/tendermint/tendermint/version" @@ -42,18 +44,6 @@ func makeTestCommit(height int64, timestamp time.Time) *types.Commit { types.BlockID{Hash: []byte(""), PartSetHeader: types.PartSetHeader{Hash: []byte(""), Total: 2}}, commitSigs) } -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 -} - func makeStateAndBlockStore(logger log.Logger) (sm.State, *BlockStore, cleanupFunc) { config := cfg.ResetTestRoot("blockchain_reactor_test") // blockDB := dbm.NewDebugDB("blockDB", dbm.NewMemDB()) @@ -144,9 +134,14 @@ var ( func TestMain(m *testing.M) { var cleanup cleanupFunc + var err error state, _, cleanup = makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer))) - block = makeBlock(1, state, new(types.Commit)) - partSet = block.MakePartSet(2) + block = factory.MakeBlock(state, 1, new(types.Commit)) + + partSet, err = block.MakePartSet(2) + if err != nil { + stdlog.Fatal(err) + } part1 = partSet.GetPart(0) part2 = partSet.GetPart(1) seenCommit1 = makeTestCommit(10, tmtime.Now()) @@ -172,8 +167,9 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) { } // save a block - block := makeBlock(bs.Height()+1, state, new(types.Commit)) - validPartSet := block.MakePartSet(2) + block := factory.MakeBlock(state, bs.Height()+1, new(types.Commit)) + 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") @@ -181,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{ @@ -375,8 +371,9 @@ func TestLoadBaseMeta(t *testing.T) { bs := NewBlockStore(dbm.NewMemDB()) for h := int64(1); h <= 10; h++ { - block := makeBlock(h, state, new(types.Commit)) - partSet := block.MakePartSet(2) + block := factory.MakeBlock(state, h, new(types.Commit)) + partSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(h, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) } @@ -443,8 +440,9 @@ func TestPruneBlocks(t *testing.T) { // make more than 1000 blocks, to test batch deletions for h := int64(1); h <= 1500; h++ { - block := makeBlock(h, state, new(types.Commit)) - partSet := block.MakePartSet(2) + block := factory.MakeBlock(state, h, new(types.Commit)) + partSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(h, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) } @@ -552,9 +550,10 @@ func TestBlockFetchAtHeight(t *testing.T) { state, bs, cleanup := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer))) defer cleanup() require.Equal(t, bs.Height(), int64(0), "initially the height should be zero") - block := makeBlock(bs.Height()+1, state, new(types.Commit)) + 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 4366f437c..bf31a80b4 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -259,7 +259,8 @@ 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. + return abci.ResponsePrepareProposal{ModifiedTx: false} } func (app *Application) Rollback() error { diff --git a/test/factory/tx.go b/test/factory/tx.go new file mode 100644 index 000000000..c97aeefc9 --- /dev/null +++ b/test/factory/tx.go @@ -0,0 +1,16 @@ +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)})) + } + return txs +} + +func MakeTenTxs(height int64) (txs []types.Tx) { + return MakeTxs(height, 10) +} diff --git a/test/maverick/consensus/state.go b/test/maverick/consensus/state.go index b9b208faa..1cb91682b 100644 --- a/test/maverick/consensus/state.go +++ b/test/maverick/consensus/state.go @@ -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,13 +1268,12 @@ 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 - var votes []*types.Vote switch { case cs.Height == cs.state.InitialHeight: // We're creating a proposal for the first block. @@ -1274,21 +1282,20 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa case cs.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = cs.LastCommit.MakeCommit() - votes = cs.LastCommit.GetVotes() 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, votes) + return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) } // Enter: any +2/3 prevotes at next round. diff --git a/types/block.go b/types/block.go index 2f0cc487b..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. 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.go b/types/evidence.go index 35acaaed1..9e71d99c2 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -459,6 +459,16 @@ func (evl EvidenceList) Has(evidence Evidence) bool { return false } +// ToABCI converts the evidence list to a slice of the ABCI protobuf messages +// for use when communicating the evidence to an application. +func (evl EvidenceList) ToABCI() []abci.Evidence { + var el []abci.Evidence + for _, e := range evl { + el = append(el, e.ABCI()...) + } + return el +} + //------------------------------------------ PROTO -------------------------------------- // EvidenceToProto is a generalized function for encoding evidence that conforms to the 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..64617a96f 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,182 @@ 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 +} + +// AddedTxs returns the transactions added by the application. +func (t TxRecordSet) AddedTxs() []Tx { + return t.added +} + +// 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) + + var size int64 + for i, cur := range allCopy { + size += int64(len(cur)) + if size > maxSizeBytes { + return fmt.Errorf("transaction data size %d exceeds maximum %d", size, maxSizeBytes) + } + + // 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) + + // 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..efb435b4c 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,160 @@ 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 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 +300,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_set.go b/types/vote_set.go index 2d6a64ece..829b54b53 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -227,6 +227,9 @@ func (voteSet *VoteSet) getVote(valIndex int32, blockKey string) (vote *Vote, ok } func (voteSet *VoteSet) GetVotes() []*Vote { + if voteSet == nil { + return nil + } return voteSet.votes } @@ -631,6 +634,7 @@ func (voteSet *VoteSet) MakeCommit() *Commit { if commitSig.ForBlock() && !v.BlockID.Equals(*voteSet.maj23) { commitSig = NewCommitSigAbsent() } + commitSigs[i] = commitSig } From b2409b3345cc43ed0f8d9e23450668fe55646569 Mon Sep 17 00:00:00 2001 From: Sergio Mena Date: Wed, 3 Aug 2022 19:39:17 +0200 Subject: [PATCH 4/4] Follow-up fixes to main `PrepareProposal` implementation (#9162) * -----start------ * [cherrypicked] state: panic on ResponsePrepareProposal validation error (#8145) * state: panic on ResponsePrepareProposal validation error * lint++ Co-authored-by: Sam Kleinman Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> * [cherrypicked] abci++: remove CheckTx call from PrepareProposal flow (#8176) * [cherrypicked] abci++: correct max-size check to only operate on added and unmodified (#8242) * [cherrypicked] Remove `ModifiedTxStatus` from the spec and the code (#8210) * Outstanding abci-gen changes to 'pb.go' files * Removed modified_tx_status from spec and protobufs * Fix sed for OSX * Regenerated abci protobufs with 'abci-proto-gen' * Code changes. UTs e2e tests passing * Recovered UT: TestPrepareProposalModifiedTxStatusFalse * Adapted UT * Fixed UT * Revert "Fix sed for OSX" This reverts commit e576708c618f0ef732498f4d348503b823b6c9e8. * Update internal/state/execution_test.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update abci/example/kvstore/kvstore.go Co-authored-by: M. J. Fromberger * Update internal/state/execution_test.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update spec/abci++/abci++_tmint_expected_behavior_002_draft.md Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Addressed some comments * Added one test that tests error at the ABCI client + Fixed some mock calls * Addressed remaining comments * Update abci/example/kvstore/kvstore.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update abci/example/kvstore/kvstore.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update abci/example/kvstore/kvstore.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update spec/abci++/abci++_tmint_expected_behavior_002_draft.md Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Addressed William's latest comments * Adressed Michael's comment * Fixed UT * Some md fixes * More md fixes * gofmt Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> Co-authored-by: M. J. Fromberger * make proto-gen * Fixed testcase on PrepareProposal error * mockery Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> Co-authored-by: Sam Kleinman Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: M. J. Fromberger --- abci/example/kvstore/kvstore.go | 5 - abci/example/kvstore/persistent_kvstore.go | 30 ++-- abci/types/application.go | 14 +- abci/types/types.pb.go | 170 ++++++++----------- consensus/mempool_test.go | 15 +- consensus/state.go | 6 +- proto/tendermint/abci/types.proto | 3 +- proxy/client.go | 2 + proxy/mocks/client_creator.go | 18 +- state/execution.go | 17 +- state/execution_test.go | 182 +++++++++++++++++++-- state/helpers_test.go | 2 +- state/test/factory/block.go | 2 +- state/validation_test.go | 2 +- test/e2e/app/app.go | 14 +- test/factory/tx.go | 13 +- types/tx.go | 19 +-- types/tx_test.go | 19 +++ 18 files changed, 347 insertions(+), 186 deletions(-) diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index d2b3f5d44..8b851ca9a 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -170,8 +170,3 @@ func (app *Application) Query(reqQuery types.RequestQuery) (resQuery types.Respo return resQuery } - -func (app *Application) PrepareProposal( - req types.RequestPrepareProposal) types.ResponsePrepareProposal { - return types.ResponsePrepareProposal{} -} diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index 465848f2a..dc740bfec 100644 --- a/abci/example/kvstore/persistent_kvstore.go +++ b/abci/example/kvstore/persistent_kvstore.go @@ -176,7 +176,7 @@ func (app *PersistentKVStoreApplication) ApplySnapshotChunk( func (app *PersistentKVStoreApplication) PrepareProposal( req types.RequestPrepareProposal) types.ResponsePrepareProposal { - return types.ResponsePrepareProposal{TxRecords: app.substPrepareTx(req.Txs)} + return types.ResponsePrepareProposal{TxRecords: app.substPrepareTx(req.Txs, req.MaxTxBytes)} } //--------------------------------------------- @@ -310,28 +310,32 @@ func (app *PersistentKVStoreApplication) execPrepareTx(tx []byte) types.Response } // substPrepareTx substitutes all the transactions prefixed with 'prepare' in the -// proposal for transactions with the prefix strips. +// 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) []*types.TxRecord { - trs := make([]*types.TxRecord, len(blockData)) +func (app *PersistentKVStoreApplication) substPrepareTx(blockData [][]byte, maxTxBytes int64) []*types.TxRecord { + trs := make([]*types.TxRecord, 0, len(blockData)) var removed []*types.TxRecord - for i, tx := range blockData { + 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, }) - trs[i] = &types.TxRecord{ - Tx: bytes.TrimPrefix(tx, []byte(PreparePrefix)), - Action: types.TxRecord_ADDED, - } - continue + txMod = bytes.TrimPrefix(tx, []byte(PreparePrefix)) + action = types.TxRecord_ADDED } - trs[i] = &types.TxRecord{ - Tx: tx, - Action: types.TxRecord_UNMODIFIED, + 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 47286e373..c30b16832 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -98,7 +98,19 @@ func (BaseApplication) ApplySnapshotChunk(req RequestApplySnapshotChunk) Respons } func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepareProposal { - return ResponsePrepareProposal{} + 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} } //------------------------------------------------------- diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 2fd9ed1a5..d61962369 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -2635,8 +2635,7 @@ func (m *ResponseApplySnapshotChunk) GetRejectSenders() []string { } type ResponsePrepareProposal struct { - ModifiedTx bool `protobuf:"varint,1,opt,name=modified_tx,json=modifiedTx,proto3" json:"modified_tx,omitempty"` - TxRecords []*TxRecord `protobuf:"bytes,2,rep,name=tx_records,json=txRecords,proto3" json:"tx_records,omitempty"` + TxRecords []*TxRecord `protobuf:"bytes,1,rep,name=tx_records,json=txRecords,proto3" json:"tx_records,omitempty"` } func (m *ResponsePrepareProposal) Reset() { *m = ResponsePrepareProposal{} } @@ -2672,13 +2671,6 @@ func (m *ResponsePrepareProposal) XXX_DiscardUnknown() { var xxx_messageInfo_ResponsePrepareProposal proto.InternalMessageInfo -func (m *ResponsePrepareProposal) GetModifiedTx() bool { - if m != nil { - return m.ModifiedTx - } - return false -} - func (m *ResponsePrepareProposal) GetTxRecords() []*TxRecord { if m != nil { return m.TxRecords @@ -3592,7 +3584,7 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3097 bytes of a gzipped FileDescriptorProto + // 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, @@ -3725,68 +3717,67 @@ var fileDescriptor_252557cfdd89a31a = []byte{ 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, 0x55, 0x0a, 0x97, 0x13, 0x78, 0x1e, 0xa3, 0x49, 0x43, 0xdb, 0x30, - 0x8f, 0x4c, 0x62, 0x68, 0x32, 0xd5, 0x52, 0xc2, 0xe0, 0x8b, 0xba, 0x63, 0x74, 0x0b, 0x80, 0x8e, - 0x35, 0x97, 0xf4, 0x6c, 0xd7, 0xf0, 0x99, 0xc1, 0xf4, 0x26, 0xec, 0x8e, 0x31, 0xd7, 0xc0, 0x65, - 0x2a, 0x4b, 0x9e, 0xfa, 0xcf, 0x34, 0xd4, 0x26, 0x8e, 0x25, 0xda, 0x80, 0xbc, 0x08, 0x3a, 0x92, - 0x7e, 0x1b, 0x71, 0x54, 0x91, 0x67, 0x58, 0xa8, 0xa2, 0x37, 0xa1, 0x44, 0x64, 0xd8, 0x3d, 0xeb, - 0xf8, 0x8b, 0x34, 0x82, 0x1f, 0x98, 0x4b, 0xd3, 0xc0, 0x02, 0xbd, 0x0d, 0xe5, 0x00, 0x5f, 0x64, - 0xa4, 0xfb, 0xd4, 0xb4, 0x79, 0x80, 0x4c, 0xd2, 0x3e, 0xb4, 0x41, 0xaf, 0x85, 0x14, 0x33, 0x37, - 0x1d, 0xea, 0x48, 0x73, 0xa1, 0x20, 0x8d, 0x7d, 0x7d, 0xb5, 0x09, 0x4b, 0x91, 0xf1, 0xa0, 0x27, - 0xa0, 0x3c, 0xd4, 0xfd, 0xac, 0x80, 0xc8, 0x56, 0x95, 0x86, 0xba, 0xc8, 0x09, 0xa0, 0xcb, 0x50, - 0x64, 0x8d, 0xc7, 0xba, 0xc0, 0xb8, 0x2c, 0x2e, 0x0c, 0xf5, 0xf1, 0xbb, 0xba, 0xa7, 0xbe, 0x0f, - 0xd5, 0x78, 0x9e, 0x8f, 0xed, 0x7f, 0xd7, 0x1e, 0x59, 0x06, 0xf7, 0x91, 0xc7, 0xa2, 0x82, 0x5e, - 0x81, 0xfc, 0x89, 0x2d, 0x20, 0x72, 0xf6, 0x1a, 0x3d, 0xb0, 0x29, 0x89, 0xe4, 0x42, 0x84, 0xb6, - 0x6a, 0x02, 0x9a, 0x4e, 0x97, 0x24, 0x74, 0xf1, 0x56, 0xbc, 0x8b, 0xa7, 0x12, 0x13, 0x2f, 0xb3, - 0xbb, 0xfa, 0x04, 0xf2, 0x1c, 0x5d, 0x19, 0x52, 0xf2, 0xe4, 0xa0, 0x64, 0xf2, 0xac, 0x8c, 0xde, - 0x07, 0xd0, 0x29, 0x75, 0xcd, 0xc3, 0x51, 0xd8, 0xc1, 0xda, 0x6c, 0x74, 0xde, 0xf4, 0xf5, 0xb6, - 0xae, 0x48, 0x98, 0xbe, 0x18, 0x9a, 0x46, 0xa0, 0x3a, 0xe2, 0x50, 0xdd, 0x85, 0x6a, 0xdc, 0x36, - 0x9a, 0xa6, 0x5f, 0x9e, 0x91, 0xa6, 0x0f, 0xd8, 0x62, 0xc0, 0x35, 0xb3, 0x22, 0x11, 0xcc, 0x2b, - 0xea, 0xa7, 0x69, 0x28, 0xb1, 0x4d, 0xcf, 0xcf, 0x6d, 0x42, 0x0e, 0x32, 0x34, 0xcd, 0x44, 0x33, - 0x6e, 0x22, 0xa9, 0x99, 0x0d, 0x52, 0xa5, 0xef, 0x04, 0xc8, 0x94, 0x5b, 0x34, 0x9a, 0xf7, 0xd3, - 0x65, 0x12, 0x8d, 0x7f, 0x29, 0x3f, 0x86, 0x9d, 0x3b, 0xf4, 0x3a, 0x14, 0xf4, 0x5e, 0x90, 0x4c, - 0xaa, 0xce, 0x70, 0xe7, 0xab, 0xae, 0x77, 0xc7, 0x9b, 0x5c, 0x13, 0x4b, 0x0b, 0xf9, 0x69, 0x99, - 0x20, 0xdf, 0xfa, 0x36, 0xf3, 0x2b, 0x74, 0xe2, 0xe0, 0x54, 0x05, 0x38, 0xd8, 0xbd, 0xdf, 0xd9, - 0xde, 0xb9, 0xbd, 0xd3, 0xda, 0x96, 0x00, 0xb5, 0xbd, 0xdd, 0xda, 0x56, 0x32, 0x4c, 0x0f, 0xb7, - 0xee, 0x77, 0x1e, 0xb4, 0xb6, 0x95, 0xac, 0xfa, 0x06, 0x94, 0x83, 0xa3, 0xc5, 0x82, 0x35, 0xdd, - 0x30, 0x5c, 0xe2, 0x79, 0x72, 0xd6, 0xfd, 0x2a, 0x4f, 0xb6, 0xdb, 0x1f, 0xcb, 0x6c, 0x63, 0x16, - 0x8b, 0x8a, 0x6a, 0x40, 0x6d, 0x82, 0x31, 0xa0, 0x37, 0xa0, 0xe8, 0x8c, 0x0e, 0x35, 0x7f, 0xe1, - 0x26, 0x10, 0xc4, 0x27, 0xee, 0xa3, 0xc3, 0x81, 0xd9, 0xbb, 0x4b, 0x4e, 0xfd, 0x69, 0x72, 0x46, - 0x87, 0x77, 0xc5, 0xfa, 0x8a, 0x5e, 0x32, 0xd1, 0x5e, 0x7e, 0x9a, 0x86, 0x92, 0xbf, 0x5f, 0xd1, - 0xff, 0x44, 0xd1, 0xc2, 0xff, 0x07, 0x93, 0x48, 0x63, 0xa4, 0xff, 0x08, 0x58, 0xdc, 0x80, 0x15, - 0xcf, 0x3c, 0xb6, 0x88, 0xa1, 0x85, 0xf1, 0x22, 0xef, 0xae, 0x84, 0x6b, 0xa2, 0xe1, 0x9e, 0x1f, - 0x2c, 0xde, 0xc9, 0x95, 0xb2, 0x4a, 0xee, 0x4e, 0xae, 0x94, 0x53, 0xf2, 0xea, 0xaf, 0xd3, 0xa0, - 0x4c, 0x1e, 0x9e, 0x7f, 0xe7, 0xc7, 0xb0, 0xbb, 0x8a, 0x1d, 0x52, 0x8d, 0xb0, 0x8f, 0x08, 0x22, - 0xe6, 0x65, 0x5c, 0x61, 0xd2, 0x96, 0x2f, 0x54, 0xff, 0x91, 0x86, 0x92, 0x0f, 0xb5, 0xe8, 0xa5, - 0xc8, 0x31, 0xae, 0xce, 0x48, 0x04, 0xfa, 0x8a, 0x61, 0x92, 0x3f, 0x3e, 0xa4, 0xcc, 0xf9, 0x87, - 0x94, 0xf4, 0xb7, 0xc6, 0xff, 0x6d, 0x96, 0x3b, 0xf7, 0x6f, 0xb3, 0x17, 0x00, 0x51, 0x9b, 0xea, - 0x03, 0xed, 0xc4, 0xa6, 0xa6, 0x75, 0xac, 0x89, 0x1d, 0x22, 0x18, 0xb8, 0xc2, 0x5b, 0x1e, 0xf0, - 0x86, 0xbd, 0x60, 0xb3, 0x04, 0x5c, 0xea, 0xbc, 0x39, 0xfb, 0x4b, 0x50, 0x90, 0x74, 0x41, 0x24, - 0xed, 0x65, 0x2d, 0xc8, 0x9c, 0xe7, 0x22, 0x99, 0xf3, 0x06, 0x94, 0x86, 0x84, 0xea, 0x9c, 0x50, - 0x8a, 0x34, 0x43, 0x50, 0xbf, 0xf1, 0x1a, 0x2c, 0x45, 0x7e, 0x9f, 0x30, 0x20, 0xdb, 0x6d, 0xbd, - 0xa7, 0xa4, 0x1a, 0xc5, 0x4f, 0x3f, 0xbf, 0x9a, 0xdd, 0x25, 0x1f, 0xb3, 0x83, 0x86, 0x5b, 0xcd, - 0x76, 0xab, 0x79, 0x57, 0x49, 0x37, 0x96, 0x3e, 0xfd, 0xfc, 0x6a, 0x11, 0x13, 0x9e, 0x3f, 0xbc, - 0xd1, 0x86, 0xe5, 0xe8, 0xaa, 0xc4, 0x0f, 0x35, 0x82, 0xea, 0xf6, 0xc1, 0xde, 0xbd, 0x9d, 0xe6, - 0x66, 0xb7, 0xa5, 0x3d, 0xe8, 0x74, 0x5b, 0x4a, 0x1a, 0x5d, 0x86, 0x0b, 0xf7, 0x76, 0xde, 0x6d, - 0x77, 0xb5, 0xe6, 0xbd, 0x9d, 0xd6, 0x6e, 0x57, 0xdb, 0xec, 0x76, 0x37, 0x9b, 0x77, 0x95, 0xcc, - 0xc6, 0x5f, 0x01, 0x6a, 0x9b, 0x5b, 0xcd, 0x1d, 0xc6, 0x96, 0xcc, 0x9e, 0x2e, 0xf3, 0xb3, 0x39, - 0x9e, 0xe5, 0x39, 0xf3, 0x35, 0x48, 0xe3, 0xec, 0xf4, 0x34, 0xba, 0x0d, 0x79, 0x9e, 0x00, 0x42, - 0x67, 0x3f, 0x0f, 0x69, 0xcc, 0xc9, 0x57, 0xb3, 0x8f, 0xe1, 0xa7, 0xe8, 0xcc, 0xf7, 0x22, 0x8d, - 0xb3, 0xd3, 0xd7, 0x08, 0x43, 0x39, 0xcc, 0xe0, 0xcc, 0x7f, 0x3f, 0xd2, 0x58, 0x20, 0xa5, 0xcd, - 0x7c, 0x86, 0x61, 0xe4, 0xfc, 0xf7, 0x14, 0x8d, 0x05, 0xee, 0x03, 0x74, 0x0f, 0x8a, 0x7e, 0xe4, - 0x3f, 0xef, 0x85, 0x47, 0x63, 0x6e, 0xba, 0x99, 0x2d, 0x81, 0xc8, 0xd0, 0x9c, 0xfd, 0x5c, 0xa5, - 0x31, 0x27, 0x77, 0x8e, 0x76, 0xa0, 0x20, 0x63, 0xa3, 0x39, 0xaf, 0x36, 0x1a, 0xf3, 0xd2, 0xc7, - 0x6c, 0xd2, 0xc2, 0xd4, 0xd7, 0xfc, 0x47, 0x38, 0x8d, 0x05, 0x7e, 0x0b, 0xa0, 0x03, 0x80, 0x48, - 0x3e, 0x66, 0x81, 0xd7, 0x35, 0x8d, 0x45, 0xd2, 0xfd, 0xa8, 0x03, 0xa5, 0x20, 0x3c, 0x9e, 0xfb, - 0xd6, 0xa5, 0x31, 0x3f, 0xef, 0x8e, 0x1e, 0x42, 0x25, 0x1e, 0x17, 0x2e, 0xf6, 0x82, 0xa5, 0xb1, - 0x60, 0x42, 0x9d, 0xf9, 0x8f, 0x07, 0x89, 0x8b, 0xbd, 0x68, 0x69, 0x2c, 0x98, 0x5f, 0x47, 0x1f, - 0xc2, 0xca, 0x74, 0x10, 0xb7, 0xf8, 0x03, 0x97, 0xc6, 0x39, 0x32, 0xee, 0x68, 0x08, 0x68, 0x46, - 0xf0, 0x77, 0x8e, 0xf7, 0x2e, 0x8d, 0xf3, 0x24, 0xe0, 0x91, 0x01, 0xb5, 0xc9, 0x88, 0x6a, 0xd1, - 0xf7, 0x2f, 0x8d, 0x85, 0x93, 0xf1, 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, - 0xc9, 0xdf, 0xac, 0x67, 0x88, 0x87, 0x05, 0x7e, 0x1d, 0xbe, 0xfc, 0xaf, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xf8, 0x2c, 0x9d, 0xd4, 0xa6, 0x28, 0x00, 0x00, + 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. @@ -6648,19 +6639,9 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 + dAtA[i] = 0xa } } - if m.ModifiedTx { - i-- - if m.ModifiedTx { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x8 - } return len(dAtA) - i, nil } @@ -8380,9 +8361,6 @@ func (m *ResponsePrepareProposal) Size() (n int) { } var l int _ = l - if m.ModifiedTx { - n += 2 - } if len(m.TxRecords) > 0 { for _, e := range m.TxRecords { l = e.Size() @@ -14215,26 +14193,6 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ModifiedTx", 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.ModifiedTx = bool(v != 0) - case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field TxRecords", wireType) } diff --git a/consensus/mempool_test.go b/consensus/mempool_test.go index 183fedefd..09cb4ec8e 100644 --- a/consensus/mempool_test.go +++ b/consensus/mempool_test.go @@ -259,5 +259,18 @@ func (app *CounterApplication) Commit() abci.ResponseCommit { func (app *CounterApplication) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{} + + 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} } diff --git a/consensus/state.go b/consensus/state.go index 8e662ea45..bce301247 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -1224,7 +1224,11 @@ func (cs *State) createProposalBlock() (*types.Block, error) { proposerAddr := cs.privValidatorPubKey.Address() - return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) + 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. diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 9b74a397f..79435c15d 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -298,8 +298,7 @@ message ResponseApplySnapshotChunk { } message ResponsePrepareProposal { - bool modified_tx = 1; - repeated TxRecord tx_records = 2; + repeated TxRecord tx_records = 1; } //---------------------------------------- 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/state/execution.go b/state/execution.go index 0659bbf61..f9875db81 100644 --- a/state/execution.go +++ b/state/execution.go @@ -129,14 +129,10 @@ 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) - } - - if !rpp.ModifiedTx { - return block, nil + // 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 } txrSet := types.NewTxRecordSet(rpp.TxRecords) @@ -149,11 +145,6 @@ func (blockExec *BlockExecutor) CreateProposalBlock( blockExec.logger.Debug("error removing transaction from the mempool", "error", err, "tx hash", rtx.Hash()) } } - for _, atx := range txrSet.AddedTxs() { - if err := blockExec.mempool.CheckTx(atx, nil, mempool.TxInfo{}); err != nil { - blockExec.logger.Error("error adding tx to the mempool", "error", err, "tx hash", atx.Hash()) - } - } itxs := txrSet.IncludedTxs() return state.MakeBlock(height, itxs, commit, evidence, proposerAddr), nil } diff --git a/state/execution_test.go b/state/execution_test.go index 5cfea42d5..00bb9b2ed 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -2,6 +2,7 @@ package state_test import ( "context" + "errors" "testing" "time" @@ -9,6 +10,7 @@ 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" @@ -20,6 +22,7 @@ import ( 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" @@ -496,7 +499,7 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { func TestEmptyPrepareProposal(t *testing.T) { const height = 2 - app := &testApp{} + app := abcimocks.NewBaseMock() cc := proxy.NewLocalClientCreator(app) proxyApp := proxy.NewAppConns(cc) err := proxyApp.Start() @@ -532,6 +535,57 @@ func TestEmptyPrepareProposal(t *testing.T) { 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. @@ -544,7 +598,7 @@ func TestPrepareProposalRemoveTxs(t *testing.T) { evpool := &mocks.EvidencePool{} evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) - txs := factory.MakeTenTxs(height) + txs := factory.MakeNTxs(height, 10) mp := &mpmocks.Mempool{} mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) @@ -555,9 +609,8 @@ func TestPrepareProposalRemoveTxs(t *testing.T) { app := abcimocks.NewBaseMock() app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ - ModifiedTx: true, - TxRecords: trs, - }, nil) + TxRecords: trs, + }) cc := proxy.NewLocalClientCreator(app) proxyApp := proxy.NewAppConns(cc) err := proxyApp.Start() @@ -587,8 +640,7 @@ func TestPrepareProposalRemoveTxs(t *testing.T) { } // TestPrepareProposalAddedTxsIncluded tests that any transactions marked as ADDED -// in the prepare proposal response are included in the block. The test also -// ensures that any transactions added are also checked into the mempool. +// in the prepare proposal response are included in the block. func TestPrepareProposalAddedTxsIncluded(t *testing.T) { const height = 2 @@ -598,10 +650,9 @@ func TestPrepareProposalAddedTxsIncluded(t *testing.T) { evpool := &mocks.EvidencePool{} evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) - txs := factory.MakeTenTxs(height) + txs := factory.MakeNTxs(height, 10) mp := &mpmocks.Mempool{} mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs[2:])) - mp.On("CheckTx", mock.Anything, mock.Anything, mock.Anything).Return(nil).Twice() trs := txsToTxRecords(types.Txs(txs)) trs[0].Action = abci.TxRecord_ADDED @@ -609,13 +660,13 @@ func TestPrepareProposalAddedTxsIncluded(t *testing.T) { app := abcimocks.NewBaseMock() app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ - ModifiedTx: true, - TxRecords: trs, - }, nil) + 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, @@ -634,8 +685,6 @@ func TestPrepareProposalAddedTxsIncluded(t *testing.T) { require.Equal(t, txs[1], block.Data.Txs[1]) mp.AssertExpectations(t) - mp.AssertCalled(t, "CheckTx", types.Tx(trs[0].Tx), mock.Anything, mock.Anything) - mp.AssertCalled(t, "CheckTx", types.Tx(trs[1].Tx), mock.Anything, mock.Anything) } // TestPrepareProposalReorderTxs tests that CreateBlock produces a block with transactions @@ -649,7 +698,7 @@ func TestPrepareProposalReorderTxs(t *testing.T) { evpool := &mocks.EvidencePool{} evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) - txs := factory.MakeTenTxs(height) + txs := factory.MakeNTxs(height, 10) mp := &mpmocks.Mempool{} mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) @@ -659,14 +708,14 @@ func TestPrepareProposalReorderTxs(t *testing.T) { app := abcimocks.NewBaseMock() app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ - ModifiedTx: true, - TxRecords: trs, - }, nil) + 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, @@ -688,6 +737,103 @@ func TestPrepareProposalReorderTxs(t *testing.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) diff --git a/state/helpers_test.go b/state/helpers_test.go index 8a7311ed9..f9a60845f 100644 --- a/state/helpers_test.go +++ b/state/helpers_test.go @@ -56,7 +56,7 @@ 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 diff --git a/state/test/factory/block.go b/state/test/factory/block.go index 35e46787c..42d88d428 100644 --- a/state/test/factory/block.go +++ b/state/test/factory/block.go @@ -42,7 +42,7 @@ func MakeBlocks(n int, state *sm.State, privVal types.PrivValidator) ([]*types.B func MakeBlock(state sm.State, height int64, c *types.Commit) *types.Block { return state.MakeBlock( height, - factory.MakeTenTxs(state.LastBlockHeight), + factory.MakeNTxs(state.LastBlockHeight, 10), c, nil, state.Validators.GetProposer().Address, diff --git a/state/validation_test.go b/state/validation_test.go index f4de55f80..9bc2f3d6c 100644 --- a/state/validation_test.go +++ b/state/validation_test.go @@ -285,7 +285,7 @@ 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) { diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index bf31a80b4..00dcc6bf9 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -260,7 +260,19 @@ func (app *Application) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) a func (app *Application) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { // None of the transactions are modified by this application. - return abci.ResponsePrepareProposal{ModifiedTx: false} + 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 *Application) Rollback() error { 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/types/tx.go b/types/tx.go index 64617a96f..ade9c94e4 100644 --- a/types/tx.go +++ b/types/tx.go @@ -172,11 +172,6 @@ func (t TxRecordSet) IncludedTxs() []Tx { return t.included } -// AddedTxs returns the transactions added by the application. -func (t TxRecordSet) AddedTxs() []Tx { - return t.added -} - // RemovedTxs returns the transactions marked for removal by the application. func (t TxRecordSet) RemovedTxs() []Tx { return t.removed @@ -206,13 +201,7 @@ func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error { // Only the slices are copied, the transaction contents are shared. allCopy := sortedCopy(t.all) - var size int64 for i, cur := range allCopy { - size += int64(len(cur)) - if size > maxSizeBytes { - return fmt.Errorf("transaction data size %d exceeds maximum %d", size, maxSizeBytes) - } - // 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()) @@ -225,6 +214,14 @@ func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error { 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) diff --git a/types/tx_test.go b/types/tx_test.go index efb435b4c..a84b0bf36 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -64,6 +64,25 @@ func TestValidateTxRecordSet(t *testing.T) { 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{ {