mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-13 00:02:52 +00:00
Compare commits
2 Commits
wb/envelop
...
stepper-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b58342a46 | ||
|
|
a9a9e1ccf0 |
22
.github/dependabot.yml
vendored
22
.github/dependabot.yml
vendored
@@ -10,16 +10,6 @@ updates:
|
||||
- T:dependencies
|
||||
- S:automerge
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
target-branch: "v0.37.x"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- T:dependencies
|
||||
- S:automerge
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
@@ -50,18 +40,6 @@ updates:
|
||||
- T:dependencies
|
||||
- S:automerge
|
||||
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
target-branch: "v0.37.x"
|
||||
# Only allow automated security-related dependency updates until we cut the
|
||||
# final v0.37.0 release.
|
||||
open-pull-requests-limit: 0
|
||||
labels:
|
||||
- T:dependencies
|
||||
- S:automerge
|
||||
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
schedule:
|
||||
|
||||
8
.github/mergify.yml
vendored
8
.github/mergify.yml
vendored
@@ -17,14 +17,6 @@ pull_request_rules:
|
||||
{{ title }} (#{{ number }})
|
||||
|
||||
{{ body }}
|
||||
- name: backport patches to v0.37.x branch
|
||||
conditions:
|
||||
- base=main
|
||||
- label=S:backport-to-v0.37.x
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- v0.37.x
|
||||
- name: backport patches to v0.34.x branch
|
||||
conditions:
|
||||
- base=main
|
||||
|
||||
8
.github/workflows/check-generated.yml
vendored
8
.github/workflows/check-generated.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.18"
|
||||
go-version: '1.18'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -42,11 +42,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.18"
|
||||
go-version: '1.18'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1 # we need a .git directory to run git diff
|
||||
fetch-depth: 1 # we need a .git directory to run git diff
|
||||
|
||||
- name: "Check protobuf generated code"
|
||||
run: |
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
export GOBIN="${tools}/bin"
|
||||
|
||||
go install github.com/bufbuild/buf/cmd/buf
|
||||
go install github.com/cosmos/gogoproto/protoc-gen-gogofaster@latest
|
||||
go install github.com/gogo/protobuf/protoc-gen-gogofaster@latest
|
||||
|
||||
make proto-gen
|
||||
|
||||
|
||||
6
.github/workflows/docker.yml
vendored
6
.github/workflows/docker.yml
vendored
@@ -6,10 +6,8 @@ on:
|
||||
branches:
|
||||
- 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]+-alpha.[0-9]+" # e.g. v0.37.0-alpha.1, v0.38.0-alpha.10
|
||||
- "v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+" # e.g. v0.37.0-beta.1, v0.38.0-beta.10
|
||||
- "v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+" # e.g. v0.37.0-rc1, v0.38.0-rc10
|
||||
- "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:
|
||||
|
||||
27
.github/workflows/e2e-nightly-34x.yml
vendored
27
.github/workflows/e2e-nightly-34x.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Notify Slack on failure
|
||||
uses: slackapi/slack-github-action@v1.22.0
|
||||
uses: slackapi/slack-github-action@v1.21.0
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
@@ -77,3 +77,28 @@ jobs:
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
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: slackapi/slack-github-action@v1.21.0
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
BRANCH: ${{ needs.e2e-nightly-test.outputs.git-branch }}
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": ":white_check_mark: Nightly E2E tests for `${{ env.BRANCH }}` passed."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
79
.github/workflows/e2e-nightly-37x.yml
vendored
79
.github/workflows/e2e-nightly-37x.yml
vendored
@@ -1,79 +0,0 @@
|
||||
# Runs randomly generated E2E testnets nightly on the v0.37.x branch.
|
||||
|
||||
# !! This file should be kept in sync with the e2e-nightly-main.yml file,
|
||||
# modulo changes to the version labels.
|
||||
|
||||
name: e2e-nightly-37x
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
|
||||
jobs:
|
||||
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', "04"]
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: 'v0.37.x'
|
||||
|
||||
- name: Capture git repo info
|
||||
id: git-info
|
||||
run: |
|
||||
echo "::set-output name=branch::`git branch --show-current`"
|
||||
echo "::set-output name=commit::`git rev-parse HEAD`"
|
||||
|
||||
- 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 tests
|
||||
|
||||
- name: Generate testnets
|
||||
working-directory: test/e2e
|
||||
# When changing -g, also change the matrix groups above
|
||||
run: ./build/generator -g 5 -d networks/nightly/
|
||||
|
||||
- name: Run ${{ matrix.p2p }} p2p testnets
|
||||
working-directory: test/e2e
|
||||
run: ./run-multiple.sh networks/nightly/*-group${{ matrix.group }}-*.toml
|
||||
|
||||
outputs:
|
||||
git-branch: ${{ steps.git-info.outputs.branch }}
|
||||
git-commit: ${{ steps.git-info.outputs.commit }}
|
||||
|
||||
e2e-nightly-fail:
|
||||
needs: e2e-nightly-test
|
||||
if: ${{ failure() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Notify Slack on failure
|
||||
uses: slackapi/slack-github-action@v1.22.0
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
BRANCH: ${{ needs.e2e-nightly-test.outputs.git-branch }}
|
||||
RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||
COMMIT_URL: "${{ github.server_url }}/${{ github.repository }}/commit/${{ needs.e2e-nightly-test.outputs.git-commit }}"
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": ":skull: Nightly E2E tests for `${{ env.BRANCH }}` failed. See the <${{ env.RUN_URL }}|run details> and the <${{ env.COMMIT_URL }}|commit> that caused the failure."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
27
.github/workflows/e2e-nightly-main.yml
vendored
27
.github/workflows/e2e-nightly-main.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Notify Slack on failure
|
||||
uses: slackapi/slack-github-action@v1.22.0
|
||||
uses: slackapi/slack-github-action@v1.21.0
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
@@ -66,3 +66,28 @@ jobs:
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
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: slackapi/slack-github-action@v1.21.0
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
BRANCH: ${{ github.ref_name }}
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": ":white_check_mark: Nightly E2E tests for `${{ env.BRANCH }}` passed."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
2
.github/workflows/fuzz-nightly.yml
vendored
2
.github/workflows/fuzz-nightly.yml
vendored
@@ -76,7 +76,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Notify Slack on failure
|
||||
uses: slackapi/slack-github-action@v1.22.0
|
||||
uses: slackapi/slack-github-action@v1.21.0
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
|
||||
41
.github/workflows/gosec.yml
vendored
41
.github/workflows/gosec.yml
vendored
@@ -1,41 +0,0 @@
|
||||
name: Run Gosec
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**/*.go'
|
||||
- 'go.mod'
|
||||
- 'go.sum'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'feature/*'
|
||||
- 'v0.37.x'
|
||||
- 'v0.34.x'
|
||||
paths:
|
||||
- '**/*.go'
|
||||
- 'go.mod'
|
||||
- 'go.sum'
|
||||
|
||||
jobs:
|
||||
Gosec:
|
||||
permissions:
|
||||
security-events: write
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO111MODULE: on
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run Gosec Security Scanner
|
||||
uses: cosmos/gosec@master
|
||||
with:
|
||||
# Let the report trigger a failure with the Github Security scanner features.
|
||||
args: "-no-fail -fmt sarif -out results.sarif ./..."
|
||||
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
# Path to SARIF file relative to the root of the repository
|
||||
sarif_file: results.sarif
|
||||
2
.github/workflows/janitor.yml
vendored
2
.github/workflows/janitor.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 3
|
||||
steps:
|
||||
- uses: styfle/cancel-workflow-action@0.10.1
|
||||
- uses: styfle/cancel-workflow-action@0.10.0
|
||||
with:
|
||||
workflow_id: 1041851,1401230,2837803
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
40
.github/workflows/pre-release.yml
vendored
40
.github/workflows/pre-release.yml
vendored
@@ -1,40 +0,0 @@
|
||||
name: "Pre-release"
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+" # e.g. v0.37.0-alpha.1, v0.38.0-alpha.10
|
||||
- "v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+" # e.g. v0.37.0-beta.1, v0.38.0-beta.10
|
||||
- "v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+" # e.g. v0.37.0-rc1, v0.38.0-rc10
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18'
|
||||
|
||||
- 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
|
||||
|
||||
# Link to CHANGELOG_PENDING.md as release notes.
|
||||
- run: echo https://github.com/tendermint/tendermint/blob/${GITHUB_REF#refs/tags/}/CHANGELOG_PENDING.md > ../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
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
2
.github/workflows/proto-lint.yml
vendored
2
.github/workflows/proto-lint.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: bufbuild/buf-setup-action@v1.8.0
|
||||
- uses: bufbuild/buf-setup-action@v1.7.0
|
||||
- uses: bufbuild/buf-lint-action@v1
|
||||
with:
|
||||
input: 'proto'
|
||||
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v6
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-pr-message: "This pull request has been automatically marked as stale because it has not had
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -38,7 +38,6 @@ terraform.tfstate
|
||||
terraform.tfstate.backup
|
||||
terraform.tfstate.d
|
||||
test/app/grpc_client
|
||||
test/loadtime/build
|
||||
test/e2e/build
|
||||
test/e2e/networks/*/
|
||||
test/logs
|
||||
|
||||
@@ -25,8 +25,7 @@ checksum:
|
||||
algorithm: sha256
|
||||
|
||||
release:
|
||||
prerelease: auto
|
||||
name_template: "{{.Version}}"
|
||||
name_template: "{{.Version}} (WARNING: BETA SOFTWARE)"
|
||||
|
||||
archives:
|
||||
- files:
|
||||
|
||||
46
CHANGELOG.md
46
CHANGELOG.md
@@ -2,38 +2,6 @@
|
||||
|
||||
Friendly reminder, we have a [bug bounty program](https://hackerone.com/cosmos).
|
||||
|
||||
## v0.34.21
|
||||
|
||||
Release highlights include:
|
||||
|
||||
- A new `[storage]` configuration section and flag `discard_abci_responses`,
|
||||
which, if enabled, discards all ABCI responses except the latest one in order
|
||||
to reduce disk space usage in the state store. When enabled, the
|
||||
`block_results` RPC endpoint can no longer function and will return an error.
|
||||
- A new CLI command, `reindex-event`, to re-index block and tx events to the
|
||||
event sinks. You can run this command when the event store backend
|
||||
dropped/disconnected or you want to replace the backend. When
|
||||
`discard_abci_responses` is enabled, you will not be able to use this command.
|
||||
|
||||
Special thanks to external contributors on this release: @rootwarp & @animart
|
||||
|
||||
### FEATURES
|
||||
|
||||
- [cli] [\#9083](https://github.com/tendermint/tendermint/issues/9083) Backport command to reindex missed events (@cmwaters)
|
||||
- [cli] [\#9107](https://github.com/tendermint/tendermint/issues/9107) Add the `p2p.external-address` argument to set the node P2P external address (@amimart)
|
||||
|
||||
### IMPROVEMENTS
|
||||
|
||||
- [config] [\#9054](https://github.com/tendermint/tendermint/issues/9054) `discard_abci_responses` flag added to discard all ABCI
|
||||
responses except the last in order to save on storage space in the state
|
||||
store (@samricotta)
|
||||
|
||||
### BUG FIXES
|
||||
|
||||
- [mempool] [\#9033](https://github.com/tendermint/tendermint/issues/9033) Rework lock discipline to mitigate callback deadlocks in the
|
||||
priority mempool
|
||||
- [cli] [\#9103](https://github.com/tendermint/tendermint/issues/9103) fix unsafe-reset-all for working with home path (@rootwarp)
|
||||
|
||||
## v0.34.20
|
||||
|
||||
Special thanks to external contributors on this release: @joeabbey @yihuang
|
||||
@@ -863,7 +831,7 @@ and a validator address plus a timestamp. Note we may remove the validator
|
||||
address & timestamp fields in the future (see ADR-25).
|
||||
|
||||
`lite2` package has been added to solve `lite` issues and introduce weak
|
||||
subjectivity interface. Refer to the [spec](https://github.com/tendermint/tendermint/tree/main/spec/consensus/light-client) for complete details.
|
||||
subjectivity interface. Refer to the [spec](https://github.com/tendermint/tendermint/blob/main/spec/consensus/light-client.md) for complete details.
|
||||
`lite` package is now deprecated and will be removed in v0.34 release.
|
||||
|
||||
### BREAKING CHANGES:
|
||||
@@ -1223,8 +1191,8 @@ Special thanks to external contributors on this release: @jon-certik, @gracenoah
|
||||
|
||||
*August 28, 2019*
|
||||
|
||||
@climber73 wrote the [Writing a Tendermint Core application in Java
|
||||
(gRPC)](https://docs.tendermint.com/v0.34/tutorials/java.html)
|
||||
@climber73 wrote the [Writing a Tendermint Core application in Java
|
||||
(gRPC)](https://github.com/tendermint/tendermint/blob/main/docs/guides/java.md)
|
||||
guide.
|
||||
|
||||
Special thanks to external contributors on this release:
|
||||
@@ -2614,7 +2582,7 @@ are affected by a change.
|
||||
|
||||
A few more breaking changes are in the works - each will come with a clear
|
||||
Architecture Decision Record (ADR) explaining the change. You can review ADRs
|
||||
[here](https://github.com/tendermint/tendermint/tree/main/docs/architecture)
|
||||
[here](https://github.com/tendermint/tendermint/tree/develop/docs/architecture)
|
||||
or in the [open Pull Requests](https://github.com/tendermint/tendermint/pulls).
|
||||
You can also check in on the [issues marked as
|
||||
breaking](https://github.com/tendermint/tendermint/issues?q=is%3Aopen+is%3Aissue+label%3Abreaking).
|
||||
@@ -2893,7 +2861,7 @@ BREAKING CHANGES:
|
||||
FEATURES
|
||||
- [cmd] Added metrics (served under `/metrics` using a Prometheus client;
|
||||
disabled by default). See the new `instrumentation` section in the config and
|
||||
[metrics](https://github.com/tendermint/tendermint/blob/main/docs/tendermint-core/metrics.md)
|
||||
[metrics](https://tendermint.readthedocs.io/projects/tools/en/develop/metrics.html)
|
||||
guide.
|
||||
- [p2p] Add IPv6 support to peering.
|
||||
- [p2p] Add `external_address` to config to allow specifying the address for
|
||||
@@ -3007,7 +2975,7 @@ BREAKING:
|
||||
|
||||
FEATURES
|
||||
|
||||
- [rpc] the RPC documentation is now published to https://github.com/tendermint/tendermint/tree/main/spec/rpc
|
||||
- [rpc] the RPC documentation is now published to https://tendermint.github.io/slate
|
||||
- [p2p] AllowDuplicateIP config option to refuse connections from same IP.
|
||||
- true by default for now, false by default in next breaking release
|
||||
- [docs] Add docs for query, tx indexing, events, pubsub
|
||||
@@ -3486,7 +3454,7 @@ containing substructs: `BaseConfig`, `P2PConfig`, `MempoolConfig`, `ConsensusCon
|
||||
|
||||
- Logger
|
||||
- Replace static `log15` logger with a simple interface, and provide a new implementation using `go-kit`.
|
||||
See our new [logging library](https://github.com/tendermint/tendermint/blob/main/libs/log/logger.go) and [blog post](https://blog.cosmos.network/abstracting-the-logger-interface-in-go-4cf96bf90bb7) for more details
|
||||
See our new [logging library](https://github.com/tendermint/tmlibs/log) and [blog post](https://tendermint.com/blog/abstracting-the-logger-interface-in-go) for more details
|
||||
- Levels `warn` and `notice` are removed (you may need to change them in your `config.toml`!)
|
||||
- Change some [function and method signatures](https://gist.github.com/ebuchman/640d5fc6c2605f73497992fe107ebe0b) to accept a logger
|
||||
|
||||
|
||||
@@ -1,37 +1,5 @@
|
||||
# Unreleased Changes
|
||||
|
||||
## v0.38.0
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- CLI/RPC/Config
|
||||
|
||||
- Apps
|
||||
|
||||
- P2P Protocol
|
||||
|
||||
- Go API
|
||||
|
||||
- Blockchain Protocol
|
||||
|
||||
- Data Storage
|
||||
- [state] \#6541 Move pruneBlocks from consensus/state to state/execution. (@JayT106)
|
||||
|
||||
- Tooling
|
||||
- [tools/tm-signer-harness] \#6498 Set OS home dir to instead of the hardcoded PATH. (@JayT106)
|
||||
|
||||
### FEATURES
|
||||
|
||||
### IMPROVEMENTS
|
||||
|
||||
- [pubsub] \#7319 Performance improvements for the event query API (@creachadair)
|
||||
- [p2p/pex] \#6509 Improve addrBook.hash performance (@cuonglm)
|
||||
- [crypto/merkle] \#6443 & \#6513 Improve HashAlternatives performance (@cuonglm, @marbar3778)
|
||||
|
||||
### BUG FIXES
|
||||
|
||||
- [docker] \#9462 ensure Docker image uses consistent version of Go
|
||||
|
||||
## v0.37.0
|
||||
|
||||
Special thanks to external contributors on this release:
|
||||
@@ -50,13 +18,7 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
|
||||
- [abci/params] \#9287 Deduplicate `ConsensusParams` and `BlockParams` so only `types` proto definitions are used (@cmwaters)
|
||||
- Remove `TimeIotaMs` and use a hard-coded 1 millisecond value to ensure monotonically increasing block times.
|
||||
- Rename `AppVersion` to `App` so as to not stutter.
|
||||
- [types] \#9287 Reduce the use of protobuf types in core logic. (@cmwaters)
|
||||
- `ConsensusParams`, `BlockParams`, `ValidatorParams`, `EvidenceParams`, `VersionParams` have become native types.
|
||||
They still utilize protobuf when being sent over the wire or written to disk.
|
||||
- Moved `ValidateConsensusParams` inside (now native type) `ConsensusParams`, and renamed it to `ValidateBasic`.
|
||||
- [abci] \#9301 New ABCI methods `PrepareProposal` and `ProcessProposal` which give the app control over transactions proposed and allows for verification of proposed blocks.
|
||||
- [abci] \#8216 Renamed `EvidenceType` to `MisbehaviorType` and `Evidence` to `Misbehavior` as a more accurate label of their contents. (@williambanfield, @sergio-mena)
|
||||
- [abci] \#9122 Renamed `LastCommitInfo` to `CommitInfo` in preparation for vote extensions. (@cmwaters)
|
||||
- [abci] \#8656, \#8901 Added cli commands for `PrepareProposal` and `ProcessProposal`. (@jmalicevic, @hvanz)
|
||||
- [abci] \#6403 Change the `key` and `value` fields from `[]byte` to `string` in the `EventAttribute` type. (@alexanderbez)
|
||||
|
||||
@@ -65,7 +27,6 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
|
||||
- Go API
|
||||
- [all] \#9144 Change spelling from British English to American (@cmwaters)
|
||||
- Rename "Subscription.Cancelled()" to "Subscription.Canceled()" in libs/pubsub
|
||||
- [crypto/sr25519] \#6526 Do not re-execute the Ed25519-style key derivation step when doing signing and verification. The derivation is now done once and only once. This breaks `sr25519.GenPrivKeyFromSecret` output compatibility. (@Yawning)
|
||||
|
||||
- Blockchain Protocol
|
||||
|
||||
@@ -74,26 +35,10 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
|
||||
- [abci] \#9301 New ABCI methods `PrepareProposal` and `ProcessProposal` which give the app control over transactions proposed and allows for verification of proposed blocks.
|
||||
|
||||
### IMPROVEMENTS
|
||||
- [crypto] \#9250 Update to use btcec v2 and the latest btcutil. (@wcsiu)
|
||||
|
||||
- [cli] \#9171 add `--hard` flag to rollback command (and a boolean to the `RollbackState` method). This will rollback
|
||||
state and remove the last block. This command can be triggered multiple times. The application must also rollback
|
||||
state to the same height. (@tsutsu, @cmwaters)
|
||||
- [proto] \#9356 Migrate from `gogo/protobuf` to `cosmos/gogoproto` (@julienrbrt)
|
||||
- [rpc] \#9276 Added `header` and `header_by_hash` queries to the RPC client (@samricotta)
|
||||
- [abci] \#5706 Added `AbciVersion` to `RequestInfo` allowing applications to check ABCI version when connecting to Tendermint. (@marbar3778)
|
||||
- [node] \#6059 Validate and complete genesis doc before saving to state store (@silasdavis)
|
||||
|
||||
- [crypto/ed25519] \#5632 Adopt zip215 `ed25519` verification. (@marbar3778)
|
||||
- [crypto/ed25519] \#6526 Use [curve25519-voi](https://github.com/oasisprotocol/curve25519-voi) for `ed25519` signing and verification. (@Yawning)
|
||||
- [crypto/sr25519] \#6526 Use [curve25519-voi](https://github.com/oasisprotocol/curve25519-voi) for `sr25519` signing and verification. (@Yawning)
|
||||
- [crypto] \#6120 Implement batch verification interface for ed25519 and sr25519. (@marbar3778 & @Yawning)
|
||||
- [types] \#6120 use batch verification for verifying commits signatures. (@marbar3778 & @cmwaters & @Yawning)
|
||||
- If the key type supports the batch verification API it will try to batch verify. If the verification fails we will single verify each signature.
|
||||
- [state] \#9505 Added logic so when pruning, the evidence period is taken into consideration and only deletes unecessary data (@samricotta)
|
||||
|
||||
### BUG FIXES
|
||||
|
||||
- [consensus] \#9229 fix round number of `enterPropose` when handling `RoundStepNewRound` timeout. (@fatcat22)
|
||||
- [docker] \#9073 enable cross platform build using docker buildx
|
||||
- [blocksync] \#9518 handle the case when the sending queue is full: retry block request after a timeout
|
||||
@@ -12,7 +12,7 @@ and hence to Tendermint.
|
||||
* We are committed to providing a friendly, safe and welcoming environment for
|
||||
all, regardless of level of experience, gender, gender identity and
|
||||
expression, sexual orientation, disability, personal appearance, body size,
|
||||
race, ethnicity, age, religion, nationality, or other similar characteristics.
|
||||
race, ethnicity, age, religion, nationality, or other similar characteristic.
|
||||
|
||||
* On Slack, please avoid using overtly sexual nicknames or other nicknames that
|
||||
might detract from a friendly, safe and welcoming environment for all.
|
||||
|
||||
@@ -12,7 +12,7 @@ landing changes in `main`.
|
||||
All work on the code base should be motivated by a [Github
|
||||
Issue](https://github.com/tendermint/tendermint/issues).
|
||||
[Search](https://github.com/tendermint/tendermint/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
|
||||
is a good place to start when looking for places to contribute. If you
|
||||
is a good place start when looking for places to contribute. If you
|
||||
would like to work on an issue which already exists, please indicate so
|
||||
by leaving a comment.
|
||||
|
||||
@@ -106,7 +106,7 @@ specify exactly the dependency you want to update, eg.
|
||||
## Protobuf
|
||||
|
||||
We use [Protocol Buffers](https://developers.google.com/protocol-buffers) along
|
||||
with [`gogoproto`](https://github.com/cosmos/gogoproto) to generate code for use
|
||||
with [`gogoproto`](https://github.com/gogo/protobuf) to generate code for use
|
||||
across Tendermint Core.
|
||||
|
||||
To generate proto stubs, lint, and check protos for breaking changes, you will
|
||||
@@ -142,6 +142,7 @@ If you are a VS Code user, you may want to add the following to your `.vscode/se
|
||||
"protoc": {
|
||||
"options": [
|
||||
"--proto_path=${workspaceRoot}/proto",
|
||||
"--proto_path=${workspaceRoot}/third_party/proto"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -213,7 +214,7 @@ Changes with multiple classifications should be doubly included (eg. a bug fix
|
||||
that is also a breaking change should be recorded under both).
|
||||
|
||||
Breaking changes are further subdivided according to the APIs/users they impact.
|
||||
Any change that affects multiple APIs/users should be recorded multiply - for
|
||||
Any change that effects multiple APIs/users should be recorded multiply - for
|
||||
instance, a change to the `Blockchain Protocol` that removes a field from the
|
||||
header should also be recorded under `CLI/RPC/Config` since the field will be
|
||||
removed from the header in RPC responses as well.
|
||||
@@ -247,7 +248,7 @@ To begin contributing, create a development branch either on `github.com/tenderm
|
||||
Make changes, and before submitting a pull request, update the `CHANGELOG_PENDING.md` to record your change. Also, run either `git rebase` or `git merge` on top of the latest `main`. (Since pull requests are squash-merged, either is fine!)
|
||||
|
||||
Update the `UPGRADING.md` if the change you've made is breaking and the
|
||||
instructions should be in place for a user on how he/she can upgrade its
|
||||
instructions should be in place for a user on how he/she can upgrade it's
|
||||
software (ABCI application, Tendermint-based blockchain, light client, wallet).
|
||||
|
||||
Once you have submitted a pull request label the pull request with either `R:minor`, if the change should be included in the next minor release, or `R:major`, if the change is meant for a major release.
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
# Use a build arg to ensure that both stages use the same,
|
||||
# hopefully current, go version.
|
||||
ARG GOLANG_BASE_IMAGE=golang:1.18-alpine
|
||||
|
||||
# stage 1 Generate Tendermint Binary
|
||||
FROM --platform=$BUILDPLATFORM $GOLANG_BASE_IMAGE as builder
|
||||
FROM --platform=$BUILDPLATFORM golang:1.18-alpine as builder
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk --no-cache add make
|
||||
@@ -12,7 +8,7 @@ WORKDIR /tendermint
|
||||
RUN TARGETPLATFORM=$TARGETPLATFORM make build-linux
|
||||
|
||||
# stage 2
|
||||
FROM $GOLANG_BASE_IMAGE
|
||||
FROM golang:1.15-alpine
|
||||
LABEL maintainer="hello@tendermint.com"
|
||||
|
||||
# Tendermint will be looking for the genesis file in /tendermint/config/genesis.json
|
||||
|
||||
@@ -8,7 +8,7 @@ Official releases can be found [here](https://github.com/tendermint/tendermint/r
|
||||
|
||||
The Dockerfile for Tendermint is not expected to change in the near future. The main file used for all builds can be found [here](https://raw.githubusercontent.com/tendermint/tendermint/main/DOCKER/Dockerfile).
|
||||
|
||||
Respective versioned files can be found at `https://raw.githubusercontent.com/tendermint/tendermint/vX.XX.XX/DOCKER/Dockerfile` (replace the Xs with the version number).
|
||||
Respective versioned files can be found <https://raw.githubusercontent.com/tendermint/tendermint/vX.XX.XX/DOCKER/Dockerfile> (replace the Xs with the version number).
|
||||
|
||||
## Quick reference
|
||||
|
||||
@@ -20,9 +20,9 @@ Respective versioned files can be found at `https://raw.githubusercontent.com/te
|
||||
|
||||
Tendermint Core is Byzantine Fault Tolerant (BFT) middleware that takes a state transition machine, written in any programming language, and securely replicates it on many machines.
|
||||
|
||||
For more background, see the [the docs](https://docs.tendermint.com/main/introduction/#quick-start).
|
||||
For more background, see the [the docs](https://docs.tendermint.com/v0.37/introduction/#quick-start).
|
||||
|
||||
To get started developing applications, see the [application developers guide](https://docs.tendermint.com/main/introduction/quick-start.html).
|
||||
To get started developing applications, see the [application developers guide](https://docs.tendermint.com/v0.37/introduction/quick-start.html).
|
||||
|
||||
## How to use this image
|
||||
|
||||
@@ -37,7 +37,7 @@ docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint node --proxy_app
|
||||
|
||||
## Local cluster
|
||||
|
||||
To run a 4-node network, see the `Makefile` in the root of [the repo](https://github.com/tendermint/tendermint/blob/main/Makefile) and run:
|
||||
To run a 4-node network, see the `Makefile` in the root of [the repo](https://github.com/tendermint/tendermint/blob/v0.37.x/Makefile) and run:
|
||||
|
||||
```sh
|
||||
make build-linux
|
||||
@@ -53,4 +53,4 @@ Note that this will build and use a different image than the ones provided here.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are most welcome! See the [contributing file](https://github.com/tendermint/tendermint/blob/main/CONTRIBUTING.md) for more information.
|
||||
Contributions are most welcome! See the [contributing file](https://github.com/tendermint/tendermint/blob/v0.37.x/CONTRIBUTING.md) for more information.
|
||||
|
||||
15
Makefile
15
Makefile
@@ -4,8 +4,14 @@ OUTPUT?=$(BUILDDIR)/tendermint
|
||||
|
||||
BUILD_TAGS?=tendermint
|
||||
|
||||
COMMIT_HASH := $(shell git rev-parse --short HEAD)
|
||||
LD_FLAGS = -X github.com/tendermint/tendermint/version.TMGitCommitHash=$(COMMIT_HASH)
|
||||
# If building a release, please checkout the version tag to get the correct version setting
|
||||
ifneq ($(shell git symbolic-ref -q --short HEAD),)
|
||||
VERSION := unreleased-$(shell git symbolic-ref -q --short HEAD)-$(shell git rev-parse HEAD)
|
||||
else
|
||||
VERSION := $(shell git describe)
|
||||
endif
|
||||
|
||||
LD_FLAGS = -X github.com/tendermint/tendermint/version.TMCoreSemVer=$(VERSION)
|
||||
BUILD_FLAGS = -mod=readonly -ldflags "$(LD_FLAGS)"
|
||||
HTTPS_GIT := https://github.com/tendermint/tendermint.git
|
||||
CGO_ENABLED ?= 0
|
||||
@@ -154,7 +160,7 @@ mockery:
|
||||
|
||||
check-proto-deps:
|
||||
ifeq (,$(shell which protoc-gen-gogofaster))
|
||||
@go install github.com/cosmos/gogoproto/protoc-gen-gogofaster@latest
|
||||
@go install github.com/gogo/protobuf/protoc-gen-gogofaster@latest
|
||||
endif
|
||||
.PHONY: check-proto-deps
|
||||
|
||||
@@ -168,7 +174,6 @@ proto-gen: check-proto-deps
|
||||
@echo "Generating Protobuf files"
|
||||
@go run github.com/bufbuild/buf/cmd/buf generate
|
||||
@mv ./proto/tendermint/abci/types.pb.go ./abci/types/
|
||||
@cp ./proto/tendermint/rpc/grpc/types.pb.go ./rpc/grpc
|
||||
.PHONY: proto-gen
|
||||
|
||||
# These targets are provided for convenience and are intended for local
|
||||
@@ -400,4 +405,4 @@ $(BUILDDIR)/packages.txt:$(GO_TEST_FILES) $(BUILDDIR)
|
||||
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=15m -race -coverprofile=$(BUILDDIR)/$*.profile.out
|
||||
cat $(BUILDDIR)/packages.txt.$* | xargs go test -mod=readonly -timeout=5m -race -coverprofile=$(BUILDDIR)/$*.profile.out
|
||||
|
||||
@@ -70,8 +70,8 @@ See the [install instructions](./docs/introduction/install.md).
|
||||
### Quick Start
|
||||
|
||||
- [Single node](./docs/introduction/quick-start.md)
|
||||
- [Local cluster using docker-compose](./docs/networks/docker-compose.md)
|
||||
- [Remote cluster using Terraform and Ansible](./docs/networks/terraform-and-ansible.md)
|
||||
- [Local cluster using docker-compose](./docs/tools/docker-compose.md)
|
||||
- [Remote cluster using Terraform and Ansible](./docs/tools/terraform-and-ansible.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -145,7 +145,7 @@ Upgrading instructions can be found in [UPGRADING.md](./UPGRADING.md).
|
||||
|
||||
## Join us!
|
||||
|
||||
Tendermint Core is maintained by [Interchain GmbH](https://interchain.io).
|
||||
Tendermint Core is maintained by [Interchain GmbH](https://interchain.berlin).
|
||||
If you'd like to work full-time on Tendermint Core,
|
||||
[we're hiring](https://interchain-gmbh.breezy.hr/)!
|
||||
|
||||
@@ -157,7 +157,7 @@ for-profit entity that also maintains [tendermint.com](https://tendermint.com).
|
||||
[bft]: https://en.wikipedia.org/wiki/Byzantine_fault_tolerance
|
||||
[smr]: https://en.wikipedia.org/wiki/State_machine_replication
|
||||
[Blockchain]: https://en.wikipedia.org/wiki/Blockchain
|
||||
[version-badge]: https://img.shields.io/github/v/release/tendermint/tendermint.svg
|
||||
[version-badge]: https://img.shields.io/github/tag/tendermint/tendermint.svg
|
||||
[version-url]: https://github.com/tendermint/tendermint/releases/latest
|
||||
[api-badge]: https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
|
||||
[api-url]: https://pkg.go.dev/github.com/tendermint/tendermint
|
||||
|
||||
181
RELEASES.md
181
RELEASES.md
@@ -22,8 +22,8 @@ We use Mergify's [backport feature](https://mergify.io/features/backports) to
|
||||
automatically backport to the needed branch. There should be a label for any
|
||||
backport branch that you'll be targeting. To notify the bot to backport a pull
|
||||
request, mark the pull request with the label corresponding to the correct
|
||||
backport branch. For example, to backport to v0.38.x, add the label
|
||||
`S:backport-to-v0.38.x`. Once the original pull request is merged, the bot will
|
||||
backport branch. For example, to backport to v0.35.x, add the label
|
||||
`S:backport-to-v0.35.x`. Once the original pull request is merged, the bot will
|
||||
try to cherry-pick the pull request to the backport branch. If the bot fails to
|
||||
backport, it will open a pull request. The author of the original pull request
|
||||
is responsible for solving the conflicts and merging the pull request.
|
||||
@@ -40,52 +40,37 @@ branches tags. See [#6072](https://github.com/tendermint/tendermint/pull/6072)
|
||||
for more context.
|
||||
|
||||
In the following example, we'll assume that we're making a backport branch for
|
||||
the 0.38.x line.
|
||||
the 0.35.x line.
|
||||
|
||||
1. Start on `main`
|
||||
|
||||
2. Ensure that there is a [branch protection
|
||||
rule](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule) for the
|
||||
branch you are about to create (you will need admin access to the repository
|
||||
in order to do this).
|
||||
|
||||
3. Create and push the backport branch:
|
||||
2. Create and push the backport branch:
|
||||
```sh
|
||||
git checkout -b v0.38.x
|
||||
git push origin v0.38.x
|
||||
git checkout -b v0.35.x
|
||||
git push origin v0.35.x
|
||||
```
|
||||
|
||||
4. Create a PR to update the documentation directory for the backport branch.
|
||||
3. Create a PR to update the documentation directory for the backport branch.
|
||||
|
||||
We rewrite any URLs pointing to `main` to point to the backport branch,
|
||||
so that generated documentation will link to the correct versions of files
|
||||
elsewhere in the repository. The following files are to be excluded from this
|
||||
search:
|
||||
We only maintain RFC and ADR documents on main, to avoid confusion. In
|
||||
addition, we rewrite Markdown URLs pointing to main to point to the
|
||||
backport branch, so that generated documentation will link to the correct
|
||||
versions of files elsewhere in the repository. For context on the latter, see
|
||||
https://github.com/tendermint/tendermint/issues/7675.
|
||||
|
||||
* [`README.md`](./README.md)
|
||||
* [`CHANGELOG.md`](./CHANGELOG.md)
|
||||
* [`UPGRADING.md`](./UPGRADING.md)
|
||||
|
||||
The following links are to always point to `main`, regardless of where they
|
||||
occur in the codebase:
|
||||
|
||||
* `https://github.com/tendermint/tendermint/blob/main/LICENSE`
|
||||
|
||||
Be sure to search for all of the following links and replace `main` with your
|
||||
corresponding branch label or version (e.g. `v0.38.x` or `v0.38`):
|
||||
|
||||
* `github.com/tendermint/tendermint/blob/main` ->
|
||||
`github.com/tendermint/tendermint/blob/v0.38.x`
|
||||
* `github.com/tendermint/tendermint/tree/main` ->
|
||||
`github.com/tendermint/tendermint/tree/v0.38.x`
|
||||
* `docs.tendermint.com/main` -> `docs.tendermint.com/v0.38`
|
||||
|
||||
Once you have updated all of the relevant documentation:
|
||||
To prepare the PR:
|
||||
```sh
|
||||
# Remove the RFC and ADR documents from the backport.
|
||||
# We only maintain these on main to avoid confusion.
|
||||
git rm -r docs/rfc docs/architecture
|
||||
|
||||
# Update absolute links to point to the backport.
|
||||
go run ./scripts/linkpatch -recur -target v0.35.x -skip-path docs/DOCS_README.md,docs/README.md docs
|
||||
|
||||
# Create and push the PR.
|
||||
git checkout -b update-docs-v038x
|
||||
git commit -m "Update docs for v0.38.x backport branch."
|
||||
git push -u origin update-docs-v038x
|
||||
git checkout -b update-docs-v035x
|
||||
git commit -m "Update docs for v0.35.x backport branch." docs
|
||||
git push -u origin update-docs-v035x
|
||||
```
|
||||
|
||||
Be sure to merge this PR before making other changes on the newly-created
|
||||
@@ -93,79 +78,74 @@ the 0.38.x line.
|
||||
|
||||
After doing these steps, go back to `main` and do the following:
|
||||
|
||||
1. Create a new workflow to run e2e nightlies for the new backport branch. (See
|
||||
1. Tag `main` as the dev branch for the _next_ minor version release and push
|
||||
it up to GitHub.
|
||||
For example:
|
||||
```sh
|
||||
git tag -a v0.36.0-dev -m "Development base for Tendermint v0.36."
|
||||
git push origin v0.36.0-dev
|
||||
```
|
||||
|
||||
2. Create a new workflow to run e2e nightlies for the new backport branch. (See
|
||||
[e2e-nightly-main.yml][e2e] for an example.)
|
||||
|
||||
2. Add a new section to the Mergify config (`.github/mergify.yml`) to enable the
|
||||
backport bot to work on this branch, and add a corresponding `S:backport-to-v0.38.x`
|
||||
3. Add a new section to the Mergify config (`.github/mergify.yml`) to enable the
|
||||
backport bot to work on this branch, and add a corresponding `S:backport-to-v0.35.x`
|
||||
[label](https://github.com/tendermint/tendermint/labels) so the bot can be triggered.
|
||||
|
||||
3. Add a new section to the Dependabot config (`.github/dependabot.yml`) to
|
||||
4. Add a new section to the Dependabot config (`.github/dependabot.yml`) to
|
||||
enable automatic update of Go dependencies on this branch. Copy and edit one
|
||||
of the existing branch configurations to set the correct `target-branch`.
|
||||
|
||||
[e2e]: https://github.com/tendermint/tendermint/blob/main/.github/workflows/e2e-nightly-main.yml
|
||||
|
||||
## Pre-releases
|
||||
## Release candidates
|
||||
|
||||
Before creating an official release, especially a minor release, we may want to
|
||||
create an alpha or beta version, or release candidate (RC) for our friends and
|
||||
partners to test out. We use git tags to create pre-releases, and we build them
|
||||
off of backport branches, for example:
|
||||
create a release candidate (RC) for our friends and partners to test out. We use
|
||||
git tags to create RCs, and we build them off of backport branches.
|
||||
|
||||
- `v0.38.0-alpha.1` - The first alpha release of `v0.38.0`. Subsequent alpha
|
||||
releases will be numbered `v0.38.0-alpha.2`, `v0.38.0-alpha.3`, etc.
|
||||
|
||||
Alpha releases are to be considered the _most_ unstable of pre-releases, and
|
||||
are most likely not yet properly QA'd. These are made available to allow early
|
||||
adopters to start integrating and testing new functionality before we're done
|
||||
with QA.
|
||||
|
||||
- `v0.38.0-beta.1` - The first beta release of `v0.38.0`. Subsequent beta
|
||||
releases will be numbered `v0.38.0-beta.2`, `v0.38.0-beta.3`, etc.
|
||||
|
||||
Beta releases can be considered more stable than alpha releases in that we
|
||||
will have QA'd them better than alpha releases, but there still may be
|
||||
minor breaking API changes if users have strong demands for such changes.
|
||||
|
||||
- `v0.38.0-rc1` - The first release candidate (RC) of `v0.38.0`. Subsequent RCs
|
||||
will be numbered `v0.38.0-rc2`, `v0.38.0-rc3`, etc.
|
||||
|
||||
RCs are considered more stable than beta releases in that we will have
|
||||
completed our QA on them. APIs will most likely be stable at this point. The
|
||||
difference between an RC and a release is that there may still be small
|
||||
changes (bug fixes, features) that may make their way into the series before
|
||||
cutting a final release.
|
||||
Tags for RCs should follow the "standard" release naming conventions, with
|
||||
`-rcX` at the end (for example, `v0.35.0-rc0`).
|
||||
|
||||
(Note that branches and tags _cannot_ have the same names, so it's important
|
||||
that these branches have distinct names from the tags/release names.)
|
||||
|
||||
If this is the first pre-release for a minor release, you'll have to make a new
|
||||
backport branch (see above). Otherwise:
|
||||
If this is the first RC for a minor release, you'll have to make a new backport
|
||||
branch (see above). Otherwise:
|
||||
|
||||
1. Start from the backport branch (e.g. `v0.38.x`).
|
||||
2. Run the integration tests and the E2E nightlies
|
||||
(which can be triggered from the GitHub UI;
|
||||
e.g., https://github.com/tendermint/tendermint/actions/workflows/e2e-nightly-37x.yml).
|
||||
3. Prepare the pre-release documentation:
|
||||
- Ensure that all relevant changes are in the `CHANGELOG_PENDING.md` file.
|
||||
This file's contents must only be included in the `CHANGELOG.md` when we
|
||||
cut final releases.
|
||||
1. Start from the backport branch (e.g. `v0.35.x`).
|
||||
2. Run the integration tests and the e2e nightlies
|
||||
(which can be triggered from the Github UI;
|
||||
e.g., https://github.com/tendermint/tendermint/actions/workflows/e2e-nightly-34x.yml).
|
||||
3. Prepare the changelog:
|
||||
- Move the changes included in `CHANGELOG_PENDING.md` into `CHANGELOG.md`. Each RC should have
|
||||
it's own changelog section. These will be squashed when the final candidate is released.
|
||||
- Ensure that there is a "release highlights" or "release summary" paragraph
|
||||
after the version heading describing what we feel are the most important
|
||||
changes in this release from a user's perspective. This paragraph should
|
||||
answer the question: "why should users upgrade to this version?", and with
|
||||
specific reasons (not generic ones like "more bug fixes").
|
||||
- Run `python ./scripts/linkify_changelog.py CHANGELOG.md` to add links for
|
||||
all PRs
|
||||
- Ensure that `UPGRADING.md` is up-to-date and includes notes on any breaking changes
|
||||
or other upgrading flows.
|
||||
4. Prepare the versioning:
|
||||
- Bump TMVersionDefault version in `version.go`
|
||||
- Bump P2P and block protocol versions in `version.go`, if necessary.
|
||||
Check the changelog for breaking changes in these components.
|
||||
- Bump ABCI protocol version in `version.go`, if necessary
|
||||
5. Open a PR with these changes against the backport branch.
|
||||
6. Once these changes have landed on the backport branch, be sure to pull them back down locally.
|
||||
7. Once you have the changes locally, create the new tag, specifying a name and a tag "message":
|
||||
`git tag -a v0.38.0-rc1 -m "Release Candidate v0.38.0-rc1`
|
||||
8. Push the tag back up to origin:
|
||||
`git push origin v0.38.0-rc1`
|
||||
4. Open a PR with these changes against the backport branch.
|
||||
5. Once these changes have landed on the backport branch, be sure to pull them back down locally.
|
||||
6. Once you have the changes locally, create the new tag, specifying a name and a tag "message":
|
||||
`git tag -a v0.35.0-rc0 -m "Release Candidate v0.35.0-rc0`
|
||||
7. Push the tag back up to origin:
|
||||
`git push origin v0.35.0-rc0`
|
||||
Now the tag should be available on the repo's releases page.
|
||||
9. Future pre-releases will continue to be built off of this branch.
|
||||
8. Future RCs will continue to be built off of this branch.
|
||||
|
||||
Note that this process should only be used for "true" RCs -- release candidates
|
||||
that, if successful, will be the next release. For more experimental "RCs,"
|
||||
create a new, short-lived branch and tag that instead.
|
||||
|
||||
## Minor release
|
||||
|
||||
@@ -176,14 +156,13 @@ branch, as described above.
|
||||
Before performing these steps, be sure the
|
||||
[Minor Release Checklist](#minor-release-checklist) has been completed.
|
||||
|
||||
1. Start on the backport branch (e.g. `v0.38.x`)
|
||||
1. Start on the backport branch (e.g. `v0.35.x`)
|
||||
2. Run integration tests (`make test_integrations`) and the e2e nightlies.
|
||||
3. Prepare the release:
|
||||
- "Squash" changes from the changelog entries for the pre-releases into a
|
||||
single entry, and add all changes included in `CHANGELOG_PENDING.md`.
|
||||
(Squashing includes both combining all entries, as well as removing or
|
||||
simplifying any intra-pre-release changes. It may also help to alphabetize
|
||||
the entries by package name.)
|
||||
- "Squash" changes from the changelog entries for the RCs into a single entry,
|
||||
and add all changes included in `CHANGELOG_PENDING.md`.
|
||||
(Squashing includes both combining all entries, as well as removing or simplifying
|
||||
any intra-RC changes. It may also help to alphabetize the entries by package name.)
|
||||
- Run `python ./scripts/linkify_changelog.py CHANGELOG.md` to add links for
|
||||
all PRs
|
||||
- Ensure that `UPGRADING.md` is up-to-date and includes notes on any breaking changes
|
||||
@@ -193,12 +172,12 @@ Before performing these steps, be sure the
|
||||
- Bump ABCI protocol version in `version.go`, if necessary
|
||||
4. Open a PR with these changes against the backport branch.
|
||||
5. Once these changes are on the backport branch, push a tag with prepared release details.
|
||||
This will trigger the actual release `v0.38.0`.
|
||||
- `git tag -a v0.38.0 -m 'Release v0.38.0'`
|
||||
- `git push origin v0.38.0`
|
||||
This will trigger the actual release `v0.35.0`.
|
||||
- `git tag -a v0.35.0 -m 'Release v0.35.0'`
|
||||
- `git push origin v0.35.0`
|
||||
6. Make sure that `main` is updated with the latest `CHANGELOG.md`, `CHANGELOG_PENDING.md`, and `UPGRADING.md`.
|
||||
7. Add the release to the documentation site generator config (see
|
||||
[DOCS\_README.md](./docs/DOCS_README.md) for more details). In summary:
|
||||
[DOCS_README.md](./docs/DOCS_README.md) for more details). In summary:
|
||||
- Start on branch `main`.
|
||||
- Add a new line at the bottom of [`docs/versions`](./docs/versions) to
|
||||
ensure the newest release is the default for the landing page.
|
||||
@@ -219,7 +198,7 @@ changes may merit a release candidate.
|
||||
|
||||
To create a patch release:
|
||||
|
||||
1. Checkout the long-lived backport branch: `git checkout v0.38.x`
|
||||
1. Checkout the long-lived backport branch: `git checkout v0.35.x`
|
||||
2. Run integration tests (`make test_integrations`) and the nightlies.
|
||||
3. Check out a new branch and prepare the release:
|
||||
- Copy `CHANGELOG_PENDING.md` to top of `CHANGELOG.md`
|
||||
@@ -230,10 +209,10 @@ To create a patch release:
|
||||
- Bump the ABCI version number, if necessary.
|
||||
(Note that ABCI follows semver, and that ABCI versions are the only versions
|
||||
which can change during patch releases, and only field additions are valid patch changes.)
|
||||
4. Open a PR with these changes that will land them back on `v0.38.x`
|
||||
4. Open a PR with these changes that will land them back on `v0.35.x`
|
||||
5. Once this change has landed on the backport branch, make sure to pull it locally, then push a tag.
|
||||
- `git tag -a v0.38.1 -m 'Release v0.38.1'`
|
||||
- `git push origin v0.38.1`
|
||||
- `git tag -a v0.35.1 -m 'Release v0.35.1'`
|
||||
- `git push origin v0.35.1`
|
||||
6. Create a pull request back to main with the CHANGELOG & version changes from the latest release.
|
||||
- Remove all `R:patch` labels from the pull requests that were included in the release.
|
||||
- Do not merge the backport branch into main.
|
||||
|
||||
@@ -7,12 +7,12 @@ Tendermint Core.
|
||||
|
||||
### ABCI Changes
|
||||
|
||||
* The `ABCIVersion` is now `1.0.0`.
|
||||
* The `ABCIVersion` is now `0.18.0`.
|
||||
|
||||
* Added new ABCI methods `PrepareProposal` and `ProcessProposal`. For details,
|
||||
please see the [spec](spec/abci/README.md). Applications upgrading to
|
||||
v0.37.0 must implement these methods, at the very minimum, as described
|
||||
[here](./spec/abci/abci++_app_requirements.md)
|
||||
[here](spec/abci/apps.md)
|
||||
* Deduplicated `ConsensusParams` and `BlockParams`.
|
||||
In the v0.34 branch they are defined both in `abci/types.proto` and `types/params.proto`.
|
||||
The definitions in `abci/types.proto` have been removed.
|
||||
|
||||
@@ -19,8 +19,8 @@ To get up and running quickly, see the [getting started guide](../docs/app-dev/g
|
||||
|
||||
A detailed description of the ABCI methods and message types is contained in:
|
||||
|
||||
- [The main spec](https://github.com/tendermint/tendermint/blob/main/spec/abci/README.md)
|
||||
- [A protobuf file](../proto/tendermint/types/types.proto)
|
||||
- [The main spec](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/abci/abci.md)
|
||||
- [A protobuf file](./types/types.proto)
|
||||
- [A Go interface](./types/application.go)
|
||||
|
||||
## Protocol Buffers
|
||||
|
||||
@@ -79,7 +79,7 @@ func NewApplication() *Application {
|
||||
func (app *Application) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
|
||||
return types.ResponseInfo{
|
||||
Data: fmt.Sprintf("{\"size\":%v}", app.state.Size),
|
||||
Version: version.ABCISemVer,
|
||||
Version: version.ABCIVersion,
|
||||
AppVersion: ProtocolVersion,
|
||||
LastBlockHeight: app.state.Height,
|
||||
LastBlockAppHash: app.state.AppHash,
|
||||
|
||||
@@ -3,7 +3,8 @@ package types
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/protoio"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/cosmos/gogoproto/jsonpb"
|
||||
"github.com/gogo/protobuf/jsonpb"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -6,11 +6,10 @@ package types
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
_ "github.com/cosmos/gogoproto/gogoproto"
|
||||
grpc1 "github.com/cosmos/gogoproto/grpc"
|
||||
proto "github.com/cosmos/gogoproto/proto"
|
||||
_ "github.com/cosmos/gogoproto/types"
|
||||
github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
_ "github.com/gogo/protobuf/types"
|
||||
github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
|
||||
crypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
|
||||
types1 "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
grpc "google.golang.org/grpc"
|
||||
@@ -3682,10 +3681,10 @@ type ABCIApplicationClient interface {
|
||||
}
|
||||
|
||||
type aBCIApplicationClient struct {
|
||||
cc grpc1.ClientConn
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewABCIApplicationClient(cc grpc1.ClientConn) ABCIApplicationClient {
|
||||
func NewABCIApplicationClient(cc *grpc.ClientConn) ABCIApplicationClient {
|
||||
return &aBCIApplicationClient{cc}
|
||||
}
|
||||
|
||||
@@ -3906,7 +3905,7 @@ func (*UnimplementedABCIApplicationServer) ProcessProposal(ctx context.Context,
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ProcessProposal not implemented")
|
||||
}
|
||||
|
||||
func RegisterABCIApplicationServer(s grpc1.Server, srv ABCIApplicationServer) {
|
||||
func RegisterABCIApplicationServer(s *grpc.Server, srv ABCIApplicationServer) {
|
||||
s.RegisterService(&_ABCIApplication_serviceDesc, srv)
|
||||
}
|
||||
|
||||
@@ -4808,7 +4807,7 @@ func (m *RequestInitChain) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
n18, err18 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time):])
|
||||
n18, err18 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):])
|
||||
if err18 != nil {
|
||||
return 0, err18
|
||||
}
|
||||
@@ -5230,7 +5229,7 @@ func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error)
|
||||
i--
|
||||
dAtA[i] = 0x3a
|
||||
}
|
||||
n22, err22 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time):])
|
||||
n22, err22 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):])
|
||||
if err22 != nil {
|
||||
return 0, err22
|
||||
}
|
||||
@@ -5318,7 +5317,7 @@ func (m *RequestProcessProposal) MarshalToSizedBuffer(dAtA []byte) (int, error)
|
||||
i--
|
||||
dAtA[i] = 0x3a
|
||||
}
|
||||
n24, err24 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time):])
|
||||
n24, err24 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):])
|
||||
if err24 != nil {
|
||||
return 0, err24
|
||||
}
|
||||
@@ -6987,7 +6986,7 @@ func (m *Misbehavior) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i--
|
||||
dAtA[i] = 0x28
|
||||
}
|
||||
n52, err52 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time):])
|
||||
n52, err52 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):])
|
||||
if err52 != nil {
|
||||
return 0, err52
|
||||
}
|
||||
@@ -7336,7 +7335,7 @@ func (m *RequestInitChain) Size() (n int) {
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time)
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time)
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
l = len(m.ChainId)
|
||||
if l > 0 {
|
||||
@@ -7548,7 +7547,7 @@ func (m *RequestPrepareProposal) Size() (n int) {
|
||||
if m.Height != 0 {
|
||||
n += 1 + sovTypes(uint64(m.Height))
|
||||
}
|
||||
l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time)
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time)
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
l = len(m.NextValidatorsHash)
|
||||
if l > 0 {
|
||||
@@ -7588,7 +7587,7 @@ func (m *RequestProcessProposal) Size() (n int) {
|
||||
if m.Height != 0 {
|
||||
n += 1 + sovTypes(uint64(m.Height))
|
||||
}
|
||||
l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time)
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time)
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
l = len(m.NextValidatorsHash)
|
||||
if l > 0 {
|
||||
@@ -8355,7 +8354,7 @@ func (m *Misbehavior) Size() (n int) {
|
||||
if m.Height != 0 {
|
||||
n += 1 + sovTypes(uint64(m.Height))
|
||||
}
|
||||
l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time)
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time)
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
if m.TotalVotingPower != 0 {
|
||||
n += 1 + sovTypes(uint64(m.TotalVotingPower))
|
||||
@@ -9347,7 +9346,7 @@ func (m *RequestInitChain) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
|
||||
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
@@ -10779,7 +10778,7 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
|
||||
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
@@ -11082,7 +11081,7 @@ func (m *RequestProcessProposal) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
|
||||
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
@@ -15397,7 +15396,7 @@ func (m *Misbehavior) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
|
||||
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
|
||||
@@ -6,4 +6,4 @@ import (
|
||||
|
||||
// TODO: eliminate this after some version refactor
|
||||
|
||||
const Version = version.ABCISemVer
|
||||
const Version = version.ABCIVersion
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
bcproto "github.com/tendermint/tendermint/proto/tendermint/blocksync"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
@@ -19,7 +19,8 @@ const (
|
||||
BlockResponseMessageFieldKeySize
|
||||
)
|
||||
|
||||
func wrapMsg(pb proto.Message) (proto.Message, error) {
|
||||
// EncodeMsg encodes a Protobuf message
|
||||
func EncodeMsg(pb proto.Message) ([]byte, error) {
|
||||
msg := bcproto.Message{}
|
||||
|
||||
switch pb := pb.(type) {
|
||||
@@ -37,7 +38,12 @@ func wrapMsg(pb proto.Message) (proto.Message, error) {
|
||||
return nil, fmt.Errorf("unknown message type %T", pb)
|
||||
}
|
||||
|
||||
return &msg, nil
|
||||
bz, err := proto.Marshal(&msg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to marshal %T: %w", pb, err)
|
||||
}
|
||||
|
||||
return bz, nil
|
||||
}
|
||||
|
||||
// DecodeMsg decodes a Protobuf message.
|
||||
@@ -48,10 +54,7 @@ func DecodeMsg(bz []byte) (proto.Message, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return UnwrapMessage(pb)
|
||||
}
|
||||
|
||||
func UnwrapMessage(pb *bcproto.Message) (proto.Message, error) {
|
||||
switch msg := pb.Sum.(type) {
|
||||
case *bcproto.Message_BlockRequest:
|
||||
return msg.BlockRequest, nil
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -80,7 +80,7 @@ func TestBcStatusResponseMessageValidateBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
//nolint:lll // ignore line length in tests
|
||||
func TestBlocksyncMessageVectors(t *testing.T) {
|
||||
func TestBlockchainMessageVectors(t *testing.T) {
|
||||
block := types.MakeBlock(int64(3), []types.Tx{types.Tx("Hello World")}, nil, nil)
|
||||
block.Version.Block = 11 // overwrite updated protocol version
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ const (
|
||||
maxTotalRequesters = 600
|
||||
maxPendingRequests = maxTotalRequesters
|
||||
maxPendingRequestsPerPeer = 20
|
||||
requestRetrySeconds = 30
|
||||
|
||||
// Minimum recv rate to ensure we're receiving blocks from a peer fast
|
||||
// enough. If a peer is not sending us data at at least that rate, we
|
||||
@@ -603,7 +602,7 @@ OUTER_LOOP:
|
||||
}
|
||||
peer = bpr.pool.pickIncrAvailablePeer(bpr.height)
|
||||
if peer == nil {
|
||||
bpr.Logger.Debug("No peers currently available; will retry shortly", "height", bpr.height)
|
||||
// log.Info("No peers available", "height", height)
|
||||
time.Sleep(requestIntervalMS * time.Millisecond)
|
||||
continue PICK_PEER_LOOP
|
||||
}
|
||||
@@ -613,7 +612,6 @@ OUTER_LOOP:
|
||||
bpr.peerID = peer.id
|
||||
bpr.mtx.Unlock()
|
||||
|
||||
to := time.NewTimer(requestRetrySeconds * time.Second)
|
||||
// Send request and wait.
|
||||
bpr.pool.sendRequest(bpr.height, peer.id)
|
||||
WAIT_LOOP:
|
||||
@@ -626,11 +624,6 @@ OUTER_LOOP:
|
||||
return
|
||||
case <-bpr.Quit():
|
||||
return
|
||||
case <-to.C:
|
||||
bpr.Logger.Debug("Retrying block request after timeout", "height", bpr.height, "peer", bpr.peerID)
|
||||
// Simulate a redo
|
||||
bpr.reset()
|
||||
continue OUTER_LOOP
|
||||
case peerID := <-bpr.redoCh:
|
||||
if peerID == bpr.peerID {
|
||||
bpr.reset()
|
||||
|
||||
@@ -30,7 +30,7 @@ const (
|
||||
)
|
||||
|
||||
type consensusReactor interface {
|
||||
// for when we switch from blocksync reactor and block sync to
|
||||
// for when we switch from blockchain reactor and block sync to
|
||||
// the consensus machine
|
||||
SwitchToConsensus(state sm.State, skipWAL bool)
|
||||
}
|
||||
@@ -143,26 +143,21 @@ func (bcR *Reactor) GetChannels() []*p2p.ChannelDescriptor {
|
||||
SendQueueCapacity: 1000,
|
||||
RecvBufferCapacity: 50 * 4096,
|
||||
RecvMessageCapacity: MaxMsgSize,
|
||||
MessageType: &bcproto.Message{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AddPeer implements Reactor by sending our state to peer.
|
||||
func (bcR *Reactor) AddPeer(peer p2p.Peer) {
|
||||
msg, err := wrapMsg(&bcproto.StatusResponse{
|
||||
msgBytes, err := EncodeMsg(&bcproto.StatusResponse{
|
||||
Base: bcR.store.Base(),
|
||||
Height: bcR.store.Height(),
|
||||
})
|
||||
Height: bcR.store.Height()})
|
||||
if err != nil {
|
||||
bcR.Logger.Error("could not convert msg to protobuf", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
peer.Send(p2p.Envelope{
|
||||
ChannelID: BlocksyncChannel,
|
||||
Message: msg,
|
||||
})
|
||||
peer.Send(BlocksyncChannel, msgBytes)
|
||||
// it's OK if send fails. will try later in poolRoutine
|
||||
|
||||
// peer is added to the pool once we receive the first
|
||||
@@ -187,79 +182,69 @@ func (bcR *Reactor) respondToPeer(msg *bcproto.BlockRequest,
|
||||
return false
|
||||
}
|
||||
|
||||
wm, err := wrapMsg(&bcproto.BlockResponse{Block: bl})
|
||||
msgBytes, err := EncodeMsg(&bcproto.BlockResponse{Block: bl})
|
||||
if err != nil {
|
||||
bcR.Logger.Error("could not convert msg to proto message", "err", err)
|
||||
bcR.Logger.Error("could not marshal msg", "err", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return src.TrySend(p2p.Envelope{
|
||||
ChannelID: BlocksyncChannel,
|
||||
Message: wm,
|
||||
})
|
||||
return src.TrySend(BlocksyncChannel, msgBytes)
|
||||
}
|
||||
|
||||
bcR.Logger.Info("Peer asking for a block we don't have", "src", src, "height", msg.Height)
|
||||
|
||||
wm, err := wrapMsg(&bcproto.NoBlockResponse{Height: msg.Height})
|
||||
msgBytes, err := EncodeMsg(&bcproto.NoBlockResponse{Height: msg.Height})
|
||||
if err != nil {
|
||||
bcR.Logger.Error("could not convert msg to protobuf", "err", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return src.TrySend(p2p.Envelope{
|
||||
ChannelID: BlocksyncChannel,
|
||||
Message: wm,
|
||||
})
|
||||
return src.TrySend(BlocksyncChannel, msgBytes)
|
||||
}
|
||||
|
||||
// Receive implements Reactor by handling 4 types of messages (look below).
|
||||
func (bcR *Reactor) Receive(e p2p.Envelope) {
|
||||
msg, err := UnwrapMessage(e.Message.(*bcproto.Message))
|
||||
func (bcR *Reactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
|
||||
msg, err := DecodeMsg(msgBytes)
|
||||
if err != nil {
|
||||
bcR.Logger.Error("Error decoding message", "src", e.Src, "chId", e.ChannelID, "err", err)
|
||||
bcR.Switch.StopPeerForError(e.Src, err)
|
||||
bcR.Logger.Error("Error decoding message", "src", src, "chId", chID, "err", err)
|
||||
bcR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = ValidateMsg(msg); err != nil {
|
||||
bcR.Logger.Error("Peer sent us invalid msg", "peer", e.Src, "msg", msg, "err", err)
|
||||
bcR.Switch.StopPeerForError(e.Src, err)
|
||||
bcR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
|
||||
bcR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
|
||||
bcR.Logger.Debug("Receive", "e.Src", e.Src, "chID", e.ChannelID, "msg", msg)
|
||||
bcR.Logger.Debug("Receive", "src", src, "chID", chID, "msg", msg)
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case *bcproto.BlockRequest:
|
||||
bcR.respondToPeer(msg, e.Src)
|
||||
bcR.respondToPeer(msg, src)
|
||||
case *bcproto.BlockResponse:
|
||||
bi, err := types.BlockFromProto(msg.Block)
|
||||
if err != nil {
|
||||
bcR.Logger.Error("Block content is invalid", "err", err)
|
||||
return
|
||||
}
|
||||
bcR.pool.AddBlock(e.Src.ID(), bi, msg.Block.Size())
|
||||
bcR.pool.AddBlock(src.ID(), bi, len(msgBytes))
|
||||
case *bcproto.StatusRequest:
|
||||
// Send peer our state.
|
||||
wm, err := wrapMsg(&bcproto.StatusResponse{
|
||||
msgBytes, err := EncodeMsg(&bcproto.StatusResponse{
|
||||
Height: bcR.store.Height(),
|
||||
Base: bcR.store.Base(),
|
||||
})
|
||||
if err != nil {
|
||||
bcR.Logger.Error("could not convert msg to proto message", "err", err)
|
||||
bcR.Logger.Error("could not convert msg to protobut", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
e.Src.TrySend(p2p.Envelope{
|
||||
ChannelID: BlocksyncChannel,
|
||||
Message: wm,
|
||||
})
|
||||
src.TrySend(BlocksyncChannel, msgBytes)
|
||||
case *bcproto.StatusResponse:
|
||||
// Got a peer status. Unverified.
|
||||
bcR.pool.SetPeerRange(e.Src.ID(), msg.Base, msg.Height)
|
||||
bcR.pool.SetPeerRange(src.ID(), msg.Base, msg.Height)
|
||||
case *bcproto.NoBlockResponse:
|
||||
bcR.Logger.Debug("Peer does not have requested block", "peer", e.Src, "height", msg.Height)
|
||||
bcR.Logger.Debug("Peer does not have requested block", "peer", src, "height", msg.Height)
|
||||
default:
|
||||
bcR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
|
||||
}
|
||||
@@ -300,15 +285,13 @@ func (bcR *Reactor) poolRoutine(stateSynced bool) {
|
||||
if peer == nil {
|
||||
continue
|
||||
}
|
||||
wm, err := wrapMsg(&bcproto.BlockRequest{Height: request.Height})
|
||||
msgBytes, err := EncodeMsg(&bcproto.BlockRequest{Height: request.Height})
|
||||
if err != nil {
|
||||
bcR.Logger.Error("could not convert msg to proto", "err", err)
|
||||
continue
|
||||
}
|
||||
queued := peer.TrySend(p2p.Envelope{
|
||||
ChannelID: BlocksyncChannel,
|
||||
Message: wm,
|
||||
})
|
||||
|
||||
queued := peer.TrySend(BlocksyncChannel, msgBytes)
|
||||
if !queued {
|
||||
bcR.Logger.Debug("Send queue is full, drop block request", "peer", peer.ID(), "height", request.Height)
|
||||
}
|
||||
@@ -423,7 +406,7 @@ FOR_LOOP:
|
||||
|
||||
// TODO: same thing for app - but we would need a way to
|
||||
// get the hash without persisting the state
|
||||
state, err = bcR.blockExec.ApplyBlock(state, firstID, first)
|
||||
state, _, err = bcR.blockExec.ApplyBlock(state, firstID, first)
|
||||
if err != nil {
|
||||
// TODO This is bad, are we zombie?
|
||||
panic(fmt.Sprintf("Failed to process committed block (%d:%X): %v", first.Height, first.Hash(), err))
|
||||
@@ -447,15 +430,13 @@ FOR_LOOP:
|
||||
|
||||
// BroadcastStatusRequest broadcasts `BlockStore` base and height.
|
||||
func (bcR *Reactor) BroadcastStatusRequest() error {
|
||||
wm, err := wrapMsg(&bcproto.StatusRequest{})
|
||||
bm, err := EncodeMsg(&bcproto.StatusRequest{})
|
||||
if err != nil {
|
||||
bcR.Logger.Error("could not convert msg to proto message", "err", err)
|
||||
return fmt.Errorf("could not convert msg to proto message: %w", err)
|
||||
bcR.Logger.Error("could not convert msg to proto", "err", err)
|
||||
return fmt.Errorf("could not convert msg to proto: %w", err)
|
||||
}
|
||||
bcR.Switch.NewBroadcast(p2p.Envelope{
|
||||
ChannelID: BlocksyncChannel,
|
||||
Message: wm,
|
||||
})
|
||||
|
||||
bcR.Switch.Broadcast(BlocksyncChannel, bm)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
mpmocks "github.com/tendermint/tendermint/mempool/mocks"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
@@ -43,7 +42,7 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
|
||||
|
||||
return &types.GenesisDoc{
|
||||
GenesisTime: tmtime.Now(),
|
||||
ChainID: test.DefaultTestChainID,
|
||||
ChainID: config.ChainID(),
|
||||
Validators: validators,
|
||||
}, privValidators
|
||||
}
|
||||
@@ -104,7 +103,7 @@ func newReactor(
|
||||
DiscardABCIResponses: false,
|
||||
})
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
|
||||
mp, sm.EmptyEvidencePool{}, blockStore)
|
||||
mp, sm.EmptyEvidencePool{})
|
||||
if err = stateStore.Save(state); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -137,7 +136,7 @@ func newReactor(
|
||||
require.NoError(t, err)
|
||||
blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()}
|
||||
|
||||
state, err = blockExec.ApplyBlock(state, blockID, thisBlock)
|
||||
state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error apply block: %w", err))
|
||||
}
|
||||
@@ -146,13 +145,13 @@ func newReactor(
|
||||
}
|
||||
|
||||
bcReactor := NewReactor(state.Copy(), blockExec, blockStore, fastSync)
|
||||
bcReactor.SetLogger(logger.With("module", "blocksync"))
|
||||
bcReactor.SetLogger(logger.With("module", "blockchain"))
|
||||
|
||||
return ReactorPair{bcReactor, proxyApp}
|
||||
}
|
||||
|
||||
func TestNoBlockResponse(t *testing.T) {
|
||||
config = test.ResetTestRoot("blocksync_reactor_test")
|
||||
config = cfg.ResetTestRoot("blockchain_reactor_test")
|
||||
defer os.RemoveAll(config.RootDir)
|
||||
genDoc, privVals := randGenesisDoc(1, false, 30)
|
||||
|
||||
@@ -164,7 +163,7 @@ func TestNoBlockResponse(t *testing.T) {
|
||||
reactorPairs[1] = newReactor(t, log.TestingLogger(), genDoc, privVals, 0)
|
||||
|
||||
p2p.MakeConnectedSwitches(config.P2P, 2, func(i int, s *p2p.Switch) *p2p.Switch {
|
||||
s.AddReactor("BLOCKSYNC", reactorPairs[i].reactor)
|
||||
s.AddReactor("BLOCKCHAIN", reactorPairs[i].reactor)
|
||||
return s
|
||||
|
||||
}, p2p.Connect2Switches)
|
||||
@@ -214,7 +213,7 @@ func TestNoBlockResponse(t *testing.T) {
|
||||
// Alternatively we could actually dial a TCP conn but
|
||||
// that seems extreme.
|
||||
func TestBadBlockStopsPeer(t *testing.T) {
|
||||
config = test.ResetTestRoot("blocksync_reactor_test")
|
||||
config = cfg.ResetTestRoot("blockchain_reactor_test")
|
||||
defer os.RemoveAll(config.RootDir)
|
||||
genDoc, privVals := randGenesisDoc(1, false, 30)
|
||||
|
||||
@@ -239,7 +238,7 @@ func TestBadBlockStopsPeer(t *testing.T) {
|
||||
reactorPairs[3] = newReactor(t, log.TestingLogger(), genDoc, privVals, 0)
|
||||
|
||||
switches := p2p.MakeConnectedSwitches(config.P2P, 4, func(i int, s *p2p.Switch) *p2p.Switch {
|
||||
s.AddReactor("BLOCKSYNC", reactorPairs[i].reactor)
|
||||
s.AddReactor("BLOCKCHAIN", reactorPairs[i].reactor)
|
||||
return s
|
||||
|
||||
}, p2p.Connect2Switches)
|
||||
@@ -278,7 +277,7 @@ func TestBadBlockStopsPeer(t *testing.T) {
|
||||
reactorPairs = append(reactorPairs, lastReactorPair)
|
||||
|
||||
switches = append(switches, p2p.MakeConnectedSwitches(config.P2P, 1, func(i int, s *p2p.Switch) *p2p.Switch {
|
||||
s.AddReactor("BLOCKSYNC", reactorPairs[len(reactorPairs)-1].reactor)
|
||||
s.AddReactor("BLOCKCHAIN", reactorPairs[len(reactorPairs)-1].reactor)
|
||||
return s
|
||||
|
||||
}, p2p.Connect2Switches)...)
|
||||
|
||||
@@ -3,7 +3,7 @@ plugins:
|
||||
- name: gogofaster
|
||||
out: ./proto/
|
||||
opt:
|
||||
- Mgoogle/protobuf/timestamp.proto=github.com/cosmos/gogoproto/types
|
||||
- Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types
|
||||
- Mgoogle/protobuf/duration.proto=github.com/golang/protobuf/ptypes/duration
|
||||
- plugins=grpc
|
||||
- paths=source_relative
|
||||
|
||||
@@ -57,18 +57,12 @@ want to use this command.
|
||||
return
|
||||
}
|
||||
|
||||
state, err := ss.Load()
|
||||
if err != nil {
|
||||
fmt.Println(reindexFailed, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := checkValidHeight(bs); err != nil {
|
||||
fmt.Println(reindexFailed, err)
|
||||
return
|
||||
}
|
||||
|
||||
bi, ti, err := loadEventSinks(config, state.ChainID)
|
||||
bi, ti, err := loadEventSinks(config)
|
||||
if err != nil {
|
||||
fmt.Println(reindexFailed, err)
|
||||
return
|
||||
@@ -100,7 +94,7 @@ func init() {
|
||||
ReIndexEventCmd.Flags().Int64Var(&endHeight, "end-height", 0, "the block height would like to finish for re-index")
|
||||
}
|
||||
|
||||
func loadEventSinks(cfg *tmcfg.Config, chainID string) (indexer.BlockIndexer, txindex.TxIndexer, error) {
|
||||
func loadEventSinks(cfg *tmcfg.Config) (indexer.BlockIndexer, txindex.TxIndexer, error) {
|
||||
switch strings.ToLower(cfg.TxIndex.Indexer) {
|
||||
case "null":
|
||||
return nil, nil, errors.New("found null event sink, please check the tx-index section in the config.toml")
|
||||
@@ -109,7 +103,7 @@ func loadEventSinks(cfg *tmcfg.Config, chainID string) (indexer.BlockIndexer, tx
|
||||
if conn == "" {
|
||||
return nil, nil, errors.New("the psql connection settings cannot be empty")
|
||||
}
|
||||
es, err := psql.NewEventSink(conn, chainID)
|
||||
es, err := psql.NewEventSink(conn, cfg.ChainID())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
|
||||
abcitypes "github.com/tendermint/tendermint/abci/types"
|
||||
tmcfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
prototmstate "github.com/tendermint/tendermint/proto/tendermint/state"
|
||||
blockmocks "github.com/tendermint/tendermint/state/indexer/mocks"
|
||||
"github.com/tendermint/tendermint/state/mocks"
|
||||
@@ -99,7 +98,7 @@ func TestLoadEventSink(t *testing.T) {
|
||||
cfg := tmcfg.TestConfig()
|
||||
cfg.TxIndex.Indexer = tc.sinks
|
||||
cfg.TxIndex.PsqlConn = tc.connURL
|
||||
_, _, err := loadEventSinks(cfg, test.DefaultTestChainID)
|
||||
_, _, err := loadEventSinks(cfg)
|
||||
if tc.loadErr {
|
||||
require.Error(t, err, idx)
|
||||
} else {
|
||||
|
||||
@@ -14,12 +14,6 @@ import (
|
||||
"github.com/tendermint/tendermint/store"
|
||||
)
|
||||
|
||||
var removeBlock bool = false
|
||||
|
||||
func init() {
|
||||
RollbackStateCmd.Flags().BoolVar(&removeBlock, "hard", false, "remove last block as well as state")
|
||||
}
|
||||
|
||||
var RollbackStateCmd = &cobra.Command{
|
||||
Use: "rollback",
|
||||
Short: "rollback tendermint state by one height",
|
||||
@@ -27,23 +21,17 @@ var RollbackStateCmd = &cobra.Command{
|
||||
A state rollback is performed to recover from an incorrect application state transition,
|
||||
when Tendermint has persisted an incorrect app hash and is thus unable to make
|
||||
progress. Rollback overwrites a state at height n with the state at height n - 1.
|
||||
The application should also roll back to height n - 1. If the --hard flag is not used,
|
||||
no blocks will be removed so upon restarting Tendermint the transactions in block n will be
|
||||
re-executed against the application. Using --hard will also remove block n. This can
|
||||
be done multiple times.
|
||||
The application should also roll back to height n - 1. No blocks are removed, so upon
|
||||
restarting Tendermint the transactions in block n will be re-executed against the
|
||||
application.
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
height, hash, err := RollbackState(config, removeBlock)
|
||||
height, hash, err := RollbackState(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to rollback state: %w", err)
|
||||
}
|
||||
|
||||
if removeBlock {
|
||||
fmt.Printf("Rolled back both state and block to height %d and hash %X\n", height, hash)
|
||||
} else {
|
||||
fmt.Printf("Rolled back state to height %d and hash %X\n", height, hash)
|
||||
}
|
||||
|
||||
fmt.Printf("Rolled back state to height %d and hash %v", height, hash)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -51,7 +39,7 @@ be done multiple times.
|
||||
// RollbackState takes the state at the current height n and overwrites it with the state
|
||||
// at height n - 1. Note state here refers to tendermint state not application state.
|
||||
// Returns the latest state height and app hash alongside an error if there was one.
|
||||
func RollbackState(config *cfg.Config, removeBlock bool) (int64, []byte, error) {
|
||||
func RollbackState(config *cfg.Config) (int64, []byte, error) {
|
||||
// use the parsed config to load the block and state store
|
||||
blockStore, stateStore, err := loadStateAndBlockStore(config)
|
||||
if err != nil {
|
||||
@@ -63,7 +51,7 @@ func RollbackState(config *cfg.Config, removeBlock bool) (int64, []byte, error)
|
||||
}()
|
||||
|
||||
// rollback the last state
|
||||
return state.Rollback(blockStore, stateStore, removeBlock)
|
||||
return state.Rollback(blockStore, stateStore)
|
||||
}
|
||||
|
||||
func loadStateAndBlockStore(config *cfg.Config) (*store.BlockStore, state.Store, error) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -14,30 +13,6 @@ var VersionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Show version info",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
tmVersion := version.TMCoreSemVer
|
||||
if version.TMGitCommitHash != "" {
|
||||
tmVersion += "+" + version.TMGitCommitHash
|
||||
}
|
||||
|
||||
if verbose {
|
||||
values, _ := json.MarshalIndent(struct {
|
||||
Tendermint string `json:"tendermint"`
|
||||
ABCI string `json:"abci"`
|
||||
BlockProtocol uint64 `json:"block_protocol"`
|
||||
P2PProtocol uint64 `json:"p2p_protocol"`
|
||||
}{
|
||||
Tendermint: tmVersion,
|
||||
ABCI: version.ABCISemVer,
|
||||
BlockProtocol: version.BlockProtocol,
|
||||
P2PProtocol: version.P2PProtocol,
|
||||
}, "", " ")
|
||||
fmt.Println(string(values))
|
||||
} else {
|
||||
fmt.Println(tmVersion)
|
||||
}
|
||||
fmt.Println(version.TMCoreSemVer)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
VersionCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Show protocol and library versions")
|
||||
}
|
||||
|
||||
102
config/config.go
102
config/config.go
@@ -7,10 +7,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -31,19 +28,6 @@ const (
|
||||
// Default is v0.
|
||||
MempoolV0 = "v0"
|
||||
MempoolV1 = "v1"
|
||||
|
||||
DefaultTendermintDir = ".tendermint"
|
||||
DefaultConfigDir = "config"
|
||||
DefaultDataDir = "data"
|
||||
|
||||
DefaultConfigFileName = "config.toml"
|
||||
DefaultGenesisJSONName = "genesis.json"
|
||||
|
||||
DefaultPrivValKeyName = "priv_validator_key.json"
|
||||
DefaultPrivValStateName = "priv_validator_state.json"
|
||||
|
||||
DefaultNodeKeyName = "node_key.json"
|
||||
DefaultAddrBookName = "addrbook.json"
|
||||
)
|
||||
|
||||
// NOTE: Most of the structs & relevant comments + the
|
||||
@@ -53,19 +37,29 @@ const (
|
||||
// config/toml.go
|
||||
// NOTE: libs/cli must know to look in the config dir!
|
||||
var (
|
||||
defaultConfigFilePath = filepath.Join(DefaultConfigDir, DefaultConfigFileName)
|
||||
defaultGenesisJSONPath = filepath.Join(DefaultConfigDir, DefaultGenesisJSONName)
|
||||
defaultPrivValKeyPath = filepath.Join(DefaultConfigDir, DefaultPrivValKeyName)
|
||||
defaultPrivValStatePath = filepath.Join(DefaultDataDir, DefaultPrivValStateName)
|
||||
DefaultTendermintDir = ".tendermint"
|
||||
defaultConfigDir = "config"
|
||||
defaultDataDir = "data"
|
||||
|
||||
defaultNodeKeyPath = filepath.Join(DefaultConfigDir, DefaultNodeKeyName)
|
||||
defaultAddrBookPath = filepath.Join(DefaultConfigDir, DefaultAddrBookName)
|
||||
defaultConfigFileName = "config.toml"
|
||||
defaultGenesisJSONName = "genesis.json"
|
||||
|
||||
defaultPrivValKeyName = "priv_validator_key.json"
|
||||
defaultPrivValStateName = "priv_validator_state.json"
|
||||
|
||||
defaultNodeKeyName = "node_key.json"
|
||||
defaultAddrBookName = "addrbook.json"
|
||||
|
||||
defaultConfigFilePath = filepath.Join(defaultConfigDir, defaultConfigFileName)
|
||||
defaultGenesisJSONPath = filepath.Join(defaultConfigDir, defaultGenesisJSONName)
|
||||
defaultPrivValKeyPath = filepath.Join(defaultConfigDir, defaultPrivValKeyName)
|
||||
defaultPrivValStatePath = filepath.Join(defaultDataDir, defaultPrivValStateName)
|
||||
|
||||
defaultNodeKeyPath = filepath.Join(defaultConfigDir, defaultNodeKeyName)
|
||||
defaultAddrBookPath = filepath.Join(defaultConfigDir, defaultAddrBookName)
|
||||
|
||||
minSubscriptionBufferSize = 100
|
||||
defaultSubscriptionBufferSize = 200
|
||||
|
||||
// taken from https://semver.org/
|
||||
semverRegexp = regexp.MustCompile(`^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`)
|
||||
)
|
||||
|
||||
// Config defines the top level configuration for a Tendermint node
|
||||
@@ -74,15 +68,18 @@ type Config struct {
|
||||
BaseConfig `mapstructure:",squash"`
|
||||
|
||||
// Options for services
|
||||
RPC *RPCConfig `mapstructure:"rpc"`
|
||||
P2P *P2PConfig `mapstructure:"p2p"`
|
||||
Mempool *MempoolConfig `mapstructure:"mempool"`
|
||||
StateSync *StateSyncConfig `mapstructure:"statesync"`
|
||||
BlockSync *BlockSyncConfig `mapstructure:"blocksync"`
|
||||
Consensus *ConsensusConfig `mapstructure:"consensus"`
|
||||
Storage *StorageConfig `mapstructure:"storage"`
|
||||
TxIndex *TxIndexConfig `mapstructure:"tx_index"`
|
||||
Instrumentation *InstrumentationConfig `mapstructure:"instrumentation"`
|
||||
RPC *RPCConfig `mapstructure:"rpc"`
|
||||
P2P *P2PConfig `mapstructure:"p2p"`
|
||||
Mempool *MempoolConfig `mapstructure:"mempool"`
|
||||
StateSync *StateSyncConfig `mapstructure:"statesync"`
|
||||
BlockSync *BlockSyncConfig `mapstructure:"blocksync"`
|
||||
//TODO(williambanfield): remove this field once v0.37 is released.
|
||||
// https://github.com/tendermint/tendermint/issues/9279
|
||||
DeprecatedFastSyncConfig map[interface{}]interface{} `mapstructure:"fastsync"`
|
||||
Consensus *ConsensusConfig `mapstructure:"consensus"`
|
||||
Storage *StorageConfig `mapstructure:"storage"`
|
||||
TxIndex *TxIndexConfig `mapstructure:"tx_index"`
|
||||
Instrumentation *InstrumentationConfig `mapstructure:"instrumentation"`
|
||||
}
|
||||
|
||||
// DefaultConfig returns a default configuration for a Tendermint node
|
||||
@@ -157,9 +154,14 @@ func (cfg *Config) ValidateBasic() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckDeprecated returns any deprecation warnings. These are printed to the operator on startup
|
||||
func (cfg *Config) CheckDeprecated() []string {
|
||||
var warnings []string
|
||||
if cfg.DeprecatedFastSyncConfig != nil {
|
||||
warnings = append(warnings, "[fastsync] table detected. This section has been renamed to [blocksync]. The values in this deprecated section will be disregarded.")
|
||||
}
|
||||
if cfg.BaseConfig.DeprecatedFastSyncMode != nil {
|
||||
warnings = append(warnings, "fast_sync key detected. This key has been renamed to block_sync. The value of this deprecated key will be disregarded.")
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
@@ -168,10 +170,8 @@ func (cfg *Config) CheckDeprecated() []string {
|
||||
|
||||
// BaseConfig defines the base configuration for a Tendermint node
|
||||
type BaseConfig struct { //nolint: maligned
|
||||
|
||||
// The version of the Tendermint binary that created
|
||||
// or last modified the config file
|
||||
Version string `mapstructure:"version"`
|
||||
// chainID is unexposed and immutable but here for convenience
|
||||
chainID string
|
||||
|
||||
// The root directory for all data.
|
||||
// This should be set in viper so it can unmarshal into this struct
|
||||
@@ -189,6 +189,10 @@ type BaseConfig struct { //nolint: maligned
|
||||
// and verifying their commits
|
||||
BlockSyncMode bool `mapstructure:"block_sync"`
|
||||
|
||||
//TODO(williambanfield): remove this field once v0.37 is released.
|
||||
// https://github.com/tendermint/tendermint/issues/9279
|
||||
DeprecatedFastSyncMode interface{} `mapstructure:"fast_sync"`
|
||||
|
||||
// Database backend: goleveldb | cleveldb | boltdb | rocksdb
|
||||
// * goleveldb (github.com/syndtr/goleveldb - most popular implementation)
|
||||
// - pure go
|
||||
@@ -246,7 +250,6 @@ type BaseConfig struct { //nolint: maligned
|
||||
// DefaultBaseConfig returns a default base configuration for a Tendermint node
|
||||
func DefaultBaseConfig() BaseConfig {
|
||||
return BaseConfig{
|
||||
Version: version.TMCoreSemVer,
|
||||
Genesis: defaultGenesisJSONPath,
|
||||
PrivValidatorKey: defaultPrivValKeyPath,
|
||||
PrivValidatorState: defaultPrivValStatePath,
|
||||
@@ -259,19 +262,24 @@ func DefaultBaseConfig() BaseConfig {
|
||||
BlockSyncMode: true,
|
||||
FilterPeers: false,
|
||||
DBBackend: "goleveldb",
|
||||
DBPath: DefaultDataDir,
|
||||
DBPath: "data",
|
||||
}
|
||||
}
|
||||
|
||||
// TestBaseConfig returns a base configuration for testing a Tendermint node
|
||||
func TestBaseConfig() BaseConfig {
|
||||
cfg := DefaultBaseConfig()
|
||||
cfg.chainID = "tendermint_test"
|
||||
cfg.ProxyApp = "kvstore"
|
||||
cfg.BlockSyncMode = false
|
||||
cfg.DBBackend = "memdb"
|
||||
return cfg
|
||||
}
|
||||
|
||||
func (cfg BaseConfig) ChainID() string {
|
||||
return cfg.chainID
|
||||
}
|
||||
|
||||
// GenesisFile returns the full path to the genesis.json file
|
||||
func (cfg BaseConfig) GenesisFile() string {
|
||||
return rootify(cfg.Genesis, cfg.RootDir)
|
||||
@@ -300,12 +308,6 @@ func (cfg BaseConfig) DBDir() string {
|
||||
// ValidateBasic performs basic validation (checking param bounds, etc.) and
|
||||
// returns an error if any check fails.
|
||||
func (cfg BaseConfig) ValidateBasic() error {
|
||||
// version on old config files aren't set so we can't expect it
|
||||
// always to exist
|
||||
if cfg.Version != "" && !semverRegexp.MatchString(cfg.Version) {
|
||||
return fmt.Errorf("invalid version string: %s", cfg.Version)
|
||||
}
|
||||
|
||||
switch cfg.LogFormat {
|
||||
case LogFormatPlain, LogFormatJSON:
|
||||
default:
|
||||
@@ -511,7 +513,7 @@ func (cfg RPCConfig) KeyFile() string {
|
||||
if filepath.IsAbs(path) {
|
||||
return path
|
||||
}
|
||||
return rootify(filepath.Join(DefaultConfigDir, path), cfg.RootDir)
|
||||
return rootify(filepath.Join(defaultConfigDir, path), cfg.RootDir)
|
||||
}
|
||||
|
||||
func (cfg RPCConfig) CertFile() string {
|
||||
@@ -519,7 +521,7 @@ func (cfg RPCConfig) CertFile() string {
|
||||
if filepath.IsAbs(path) {
|
||||
return path
|
||||
}
|
||||
return rootify(filepath.Join(DefaultConfigDir, path), cfg.RootDir)
|
||||
return rootify(filepath.Join(defaultConfigDir, path), cfg.RootDir)
|
||||
}
|
||||
|
||||
func (cfg RPCConfig) IsTLSEnabled() bool {
|
||||
@@ -968,7 +970,7 @@ type ConsensusConfig struct {
|
||||
// DefaultConsensusConfig returns a default configuration for the consensus service
|
||||
func DefaultConsensusConfig() *ConsensusConfig {
|
||||
return &ConsensusConfig{
|
||||
WalPath: filepath.Join(DefaultDataDir, "cs.wal", "wal"),
|
||||
WalPath: filepath.Join(defaultDataDir, "cs.wal", "wal"),
|
||||
TimeoutPropose: 3000 * time.Millisecond,
|
||||
TimeoutProposeDelta: 500 * time.Millisecond,
|
||||
TimeoutPrevote: 1000 * time.Millisecond,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package config_test
|
||||
package config
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
@@ -7,15 +7,13 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/config"
|
||||
)
|
||||
|
||||
func TestDefaultConfig(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// set up some defaults
|
||||
cfg := config.DefaultConfig()
|
||||
cfg := DefaultConfig()
|
||||
assert.NotNil(cfg.P2P)
|
||||
assert.NotNil(cfg.Mempool)
|
||||
assert.NotNil(cfg.Consensus)
|
||||
@@ -33,7 +31,7 @@ func TestDefaultConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfigValidateBasic(t *testing.T) {
|
||||
cfg := config.DefaultConfig()
|
||||
cfg := DefaultConfig()
|
||||
assert.NoError(t, cfg.ValidateBasic())
|
||||
|
||||
// tamper with timeout_propose
|
||||
@@ -43,7 +41,7 @@ func TestConfigValidateBasic(t *testing.T) {
|
||||
|
||||
func TestTLSConfiguration(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
cfg := config.DefaultConfig()
|
||||
cfg := DefaultConfig()
|
||||
cfg.SetRoot("/home/user")
|
||||
|
||||
cfg.RPC.TLSCertFile = "file.crt"
|
||||
@@ -58,7 +56,7 @@ func TestTLSConfiguration(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBaseConfigValidateBasic(t *testing.T) {
|
||||
cfg := config.TestBaseConfig()
|
||||
cfg := TestBaseConfig()
|
||||
assert.NoError(t, cfg.ValidateBasic())
|
||||
|
||||
// tamper with log format
|
||||
@@ -67,7 +65,7 @@ func TestBaseConfigValidateBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRPCConfigValidateBasic(t *testing.T) {
|
||||
cfg := config.TestRPCConfig()
|
||||
cfg := TestRPCConfig()
|
||||
assert.NoError(t, cfg.ValidateBasic())
|
||||
|
||||
fieldsToTest := []string{
|
||||
@@ -88,7 +86,7 @@ func TestRPCConfigValidateBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestP2PConfigValidateBasic(t *testing.T) {
|
||||
cfg := config.TestP2PConfig()
|
||||
cfg := TestP2PConfig()
|
||||
assert.NoError(t, cfg.ValidateBasic())
|
||||
|
||||
fieldsToTest := []string{
|
||||
@@ -108,7 +106,7 @@ func TestP2PConfigValidateBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMempoolConfigValidateBasic(t *testing.T) {
|
||||
cfg := config.TestMempoolConfig()
|
||||
cfg := TestMempoolConfig()
|
||||
assert.NoError(t, cfg.ValidateBasic())
|
||||
|
||||
fieldsToTest := []string{
|
||||
@@ -126,12 +124,12 @@ func TestMempoolConfigValidateBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateSyncConfigValidateBasic(t *testing.T) {
|
||||
cfg := config.TestStateSyncConfig()
|
||||
cfg := TestStateSyncConfig()
|
||||
require.NoError(t, cfg.ValidateBasic())
|
||||
}
|
||||
|
||||
func TestBlockSyncConfigValidateBasic(t *testing.T) {
|
||||
cfg := config.TestBlockSyncConfig()
|
||||
cfg := TestBlockSyncConfig()
|
||||
assert.NoError(t, cfg.ValidateBasic())
|
||||
|
||||
// tamper with version
|
||||
@@ -145,33 +143,33 @@ func TestBlockSyncConfigValidateBasic(t *testing.T) {
|
||||
func TestConsensusConfig_ValidateBasic(t *testing.T) {
|
||||
//nolint: lll
|
||||
testcases := map[string]struct {
|
||||
modify func(*config.ConsensusConfig)
|
||||
modify func(*ConsensusConfig)
|
||||
expectErr bool
|
||||
}{
|
||||
"TimeoutPropose": {func(c *config.ConsensusConfig) { c.TimeoutPropose = time.Second }, false},
|
||||
"TimeoutPropose negative": {func(c *config.ConsensusConfig) { c.TimeoutPropose = -1 }, true},
|
||||
"TimeoutProposeDelta": {func(c *config.ConsensusConfig) { c.TimeoutProposeDelta = time.Second }, false},
|
||||
"TimeoutProposeDelta negative": {func(c *config.ConsensusConfig) { c.TimeoutProposeDelta = -1 }, true},
|
||||
"TimeoutPrevote": {func(c *config.ConsensusConfig) { c.TimeoutPrevote = time.Second }, false},
|
||||
"TimeoutPrevote negative": {func(c *config.ConsensusConfig) { c.TimeoutPrevote = -1 }, true},
|
||||
"TimeoutPrevoteDelta": {func(c *config.ConsensusConfig) { c.TimeoutPrevoteDelta = time.Second }, false},
|
||||
"TimeoutPrevoteDelta negative": {func(c *config.ConsensusConfig) { c.TimeoutPrevoteDelta = -1 }, true},
|
||||
"TimeoutPrecommit": {func(c *config.ConsensusConfig) { c.TimeoutPrecommit = time.Second }, false},
|
||||
"TimeoutPrecommit negative": {func(c *config.ConsensusConfig) { c.TimeoutPrecommit = -1 }, true},
|
||||
"TimeoutPrecommitDelta": {func(c *config.ConsensusConfig) { c.TimeoutPrecommitDelta = time.Second }, false},
|
||||
"TimeoutPrecommitDelta negative": {func(c *config.ConsensusConfig) { c.TimeoutPrecommitDelta = -1 }, true},
|
||||
"TimeoutCommit": {func(c *config.ConsensusConfig) { c.TimeoutCommit = time.Second }, false},
|
||||
"TimeoutCommit negative": {func(c *config.ConsensusConfig) { c.TimeoutCommit = -1 }, true},
|
||||
"PeerGossipSleepDuration": {func(c *config.ConsensusConfig) { c.PeerGossipSleepDuration = time.Second }, false},
|
||||
"PeerGossipSleepDuration negative": {func(c *config.ConsensusConfig) { c.PeerGossipSleepDuration = -1 }, true},
|
||||
"PeerQueryMaj23SleepDuration": {func(c *config.ConsensusConfig) { c.PeerQueryMaj23SleepDuration = time.Second }, false},
|
||||
"PeerQueryMaj23SleepDuration negative": {func(c *config.ConsensusConfig) { c.PeerQueryMaj23SleepDuration = -1 }, true},
|
||||
"DoubleSignCheckHeight negative": {func(c *config.ConsensusConfig) { c.DoubleSignCheckHeight = -1 }, true},
|
||||
"TimeoutPropose": {func(c *ConsensusConfig) { c.TimeoutPropose = time.Second }, false},
|
||||
"TimeoutPropose negative": {func(c *ConsensusConfig) { c.TimeoutPropose = -1 }, true},
|
||||
"TimeoutProposeDelta": {func(c *ConsensusConfig) { c.TimeoutProposeDelta = time.Second }, false},
|
||||
"TimeoutProposeDelta negative": {func(c *ConsensusConfig) { c.TimeoutProposeDelta = -1 }, true},
|
||||
"TimeoutPrevote": {func(c *ConsensusConfig) { c.TimeoutPrevote = time.Second }, false},
|
||||
"TimeoutPrevote negative": {func(c *ConsensusConfig) { c.TimeoutPrevote = -1 }, true},
|
||||
"TimeoutPrevoteDelta": {func(c *ConsensusConfig) { c.TimeoutPrevoteDelta = time.Second }, false},
|
||||
"TimeoutPrevoteDelta negative": {func(c *ConsensusConfig) { c.TimeoutPrevoteDelta = -1 }, true},
|
||||
"TimeoutPrecommit": {func(c *ConsensusConfig) { c.TimeoutPrecommit = time.Second }, false},
|
||||
"TimeoutPrecommit negative": {func(c *ConsensusConfig) { c.TimeoutPrecommit = -1 }, true},
|
||||
"TimeoutPrecommitDelta": {func(c *ConsensusConfig) { c.TimeoutPrecommitDelta = time.Second }, false},
|
||||
"TimeoutPrecommitDelta negative": {func(c *ConsensusConfig) { c.TimeoutPrecommitDelta = -1 }, true},
|
||||
"TimeoutCommit": {func(c *ConsensusConfig) { c.TimeoutCommit = time.Second }, false},
|
||||
"TimeoutCommit negative": {func(c *ConsensusConfig) { c.TimeoutCommit = -1 }, true},
|
||||
"PeerGossipSleepDuration": {func(c *ConsensusConfig) { c.PeerGossipSleepDuration = time.Second }, false},
|
||||
"PeerGossipSleepDuration negative": {func(c *ConsensusConfig) { c.PeerGossipSleepDuration = -1 }, true},
|
||||
"PeerQueryMaj23SleepDuration": {func(c *ConsensusConfig) { c.PeerQueryMaj23SleepDuration = time.Second }, false},
|
||||
"PeerQueryMaj23SleepDuration negative": {func(c *ConsensusConfig) { c.PeerQueryMaj23SleepDuration = -1 }, true},
|
||||
"DoubleSignCheckHeight negative": {func(c *ConsensusConfig) { c.DoubleSignCheckHeight = -1 }, true},
|
||||
}
|
||||
for desc, tc := range testcases {
|
||||
tc := tc // appease linter
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
cfg := config.DefaultConsensusConfig()
|
||||
cfg := DefaultConsensusConfig()
|
||||
tc.modify(cfg)
|
||||
|
||||
err := cfg.ValidateBasic()
|
||||
@@ -185,7 +183,7 @@ func TestConsensusConfig_ValidateBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInstrumentationConfigValidateBasic(t *testing.T) {
|
||||
cfg := config.TestInstrumentationConfig()
|
||||
cfg := TestInstrumentationConfig()
|
||||
assert.NoError(t, cfg.ValidateBasic())
|
||||
|
||||
// tamper with maximum open connections
|
||||
|
||||
109
config/toml.go
109
config/toml.go
@@ -2,6 +2,8 @@ package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
@@ -32,10 +34,10 @@ func EnsureRoot(rootDir string) {
|
||||
if err := tmos.EnsureDir(rootDir, DefaultDirPerm); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
if err := tmos.EnsureDir(filepath.Join(rootDir, DefaultConfigDir), DefaultDirPerm); err != nil {
|
||||
if err := tmos.EnsureDir(filepath.Join(rootDir, defaultConfigDir), DefaultDirPerm); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
if err := tmos.EnsureDir(filepath.Join(rootDir, DefaultDataDir), DefaultDirPerm); err != nil {
|
||||
if err := tmos.EnsureDir(filepath.Join(rootDir, defaultDataDir), DefaultDirPerm); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
@@ -74,10 +76,6 @@ const defaultConfigTemplate = `# This is a TOML config file.
|
||||
# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable
|
||||
# or --home cmd flag.
|
||||
|
||||
# The version of the Tendermint binary that created or
|
||||
# last modified the config file. Do not modify this.
|
||||
version = "{{ .BaseConfig.Version }}"
|
||||
|
||||
#######################################################################
|
||||
### Main Base Config Options ###
|
||||
#######################################################################
|
||||
@@ -487,7 +485,6 @@ peer_query_maj23_sleep_duration = "{{ .Consensus.PeerQueryMaj23SleepDuration }}"
|
||||
#######################################################
|
||||
### Storage Configuration Options ###
|
||||
#######################################################
|
||||
[storage]
|
||||
|
||||
# Set to true to discard ABCI responses from the state store, which can save a
|
||||
# considerable amount of disk space. Set to false to ensure ABCI responses are
|
||||
@@ -539,3 +536,101 @@ max_open_connections = {{ .Instrumentation.MaxOpenConnections }}
|
||||
# Instrumentation namespace
|
||||
namespace = "{{ .Instrumentation.Namespace }}"
|
||||
`
|
||||
|
||||
/****** these are for test settings ***********/
|
||||
|
||||
func ResetTestRoot(testName string) *Config {
|
||||
return ResetTestRootWithChainID(testName, "")
|
||||
}
|
||||
|
||||
func ResetTestRootWithChainID(testName string, chainID string) *Config {
|
||||
// create a unique, concurrency-safe test directory under os.TempDir()
|
||||
rootDir, err := os.MkdirTemp("", fmt.Sprintf("%s-%s_", chainID, testName))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// ensure config and data subdirs are created
|
||||
if err := tmos.EnsureDir(filepath.Join(rootDir, defaultConfigDir), DefaultDirPerm); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := tmos.EnsureDir(filepath.Join(rootDir, defaultDataDir), DefaultDirPerm); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
baseConfig := DefaultBaseConfig()
|
||||
configFilePath := filepath.Join(rootDir, defaultConfigFilePath)
|
||||
genesisFilePath := filepath.Join(rootDir, baseConfig.Genesis)
|
||||
privKeyFilePath := filepath.Join(rootDir, baseConfig.PrivValidatorKey)
|
||||
privStateFilePath := filepath.Join(rootDir, baseConfig.PrivValidatorState)
|
||||
|
||||
// Write default config file if missing.
|
||||
if !tmos.FileExists(configFilePath) {
|
||||
writeDefaultConfigFile(configFilePath)
|
||||
}
|
||||
if !tmos.FileExists(genesisFilePath) {
|
||||
if chainID == "" {
|
||||
chainID = "tendermint_test"
|
||||
}
|
||||
testGenesis := fmt.Sprintf(testGenesisFmt, chainID)
|
||||
tmos.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644)
|
||||
}
|
||||
// we always overwrite the priv val
|
||||
tmos.MustWriteFile(privKeyFilePath, []byte(testPrivValidatorKey), 0644)
|
||||
tmos.MustWriteFile(privStateFilePath, []byte(testPrivValidatorState), 0644)
|
||||
|
||||
config := TestConfig().SetRoot(rootDir)
|
||||
return config
|
||||
}
|
||||
|
||||
var testGenesisFmt = `{
|
||||
"genesis_time": "2018-10-10T08:20:13.695936996Z",
|
||||
"chain_id": "%s",
|
||||
"initial_height": "1",
|
||||
"consensus_params": {
|
||||
"block": {
|
||||
"max_bytes": "22020096",
|
||||
"max_gas": "-1",
|
||||
"time_iota_ms": "10"
|
||||
},
|
||||
"evidence": {
|
||||
"max_age_num_blocks": "100000",
|
||||
"max_age_duration": "172800000000000",
|
||||
"max_bytes": "1048576"
|
||||
},
|
||||
"validator": {
|
||||
"pub_key_types": [
|
||||
"ed25519"
|
||||
]
|
||||
},
|
||||
"version": {}
|
||||
},
|
||||
"validators": [
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
|
||||
},
|
||||
"power": "10",
|
||||
"name": ""
|
||||
}
|
||||
],
|
||||
"app_hash": ""
|
||||
}`
|
||||
|
||||
var testPrivValidatorKey = `{
|
||||
"address": "A3258DCBF45DCA0DF052981870F2D1441A36D145",
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
|
||||
},
|
||||
"priv_key": {
|
||||
"type": "tendermint/PrivKeyEd25519",
|
||||
"value": "EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ=="
|
||||
}
|
||||
}`
|
||||
|
||||
var testPrivValidatorState = `{
|
||||
"height": "0",
|
||||
"round": 0,
|
||||
"step": 0
|
||||
}`
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
package config_test
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
)
|
||||
|
||||
func ensureFiles(t *testing.T, rootDir string, files ...string) {
|
||||
for _, f := range files {
|
||||
p := filepath.Join(rootDir, f)
|
||||
p := rootify(rootDir, f)
|
||||
_, err := os.Stat(p)
|
||||
assert.NoError(t, err, p)
|
||||
assert.Nil(t, err, p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,13 +27,15 @@ func TestEnsureRoot(t *testing.T) {
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// create root dir
|
||||
config.EnsureRoot(tmpDir)
|
||||
EnsureRoot(tmpDir)
|
||||
|
||||
// make sure config is set properly
|
||||
data, err := os.ReadFile(filepath.Join(tmpDir, config.DefaultConfigDir, config.DefaultConfigFileName))
|
||||
data, err := os.ReadFile(filepath.Join(tmpDir, defaultConfigFilePath))
|
||||
require.Nil(err)
|
||||
|
||||
assertValidConfig(t, string(data))
|
||||
if !checkConfig(string(data)) {
|
||||
t.Fatalf("config file missing some information")
|
||||
}
|
||||
|
||||
ensureFiles(t, tmpDir, "data")
|
||||
}
|
||||
@@ -43,30 +43,35 @@ func TestEnsureRoot(t *testing.T) {
|
||||
func TestEnsureTestRoot(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
testName := "ensureTestRoot"
|
||||
|
||||
// create root dir
|
||||
cfg := test.ResetTestRoot("ensureTestRoot")
|
||||
cfg := ResetTestRoot(testName)
|
||||
defer os.RemoveAll(cfg.RootDir)
|
||||
rootDir := cfg.RootDir
|
||||
|
||||
// make sure config is set properly
|
||||
data, err := os.ReadFile(filepath.Join(rootDir, config.DefaultConfigDir, config.DefaultConfigFileName))
|
||||
data, err := os.ReadFile(filepath.Join(rootDir, defaultConfigFilePath))
|
||||
require.Nil(err)
|
||||
|
||||
assertValidConfig(t, string(data))
|
||||
if !checkConfig(string(data)) {
|
||||
t.Fatalf("config file missing some information")
|
||||
}
|
||||
|
||||
// TODO: make sure the cfg returned and testconfig are the same!
|
||||
baseConfig := config.DefaultBaseConfig()
|
||||
ensureFiles(t, rootDir, config.DefaultDataDir, baseConfig.Genesis, baseConfig.PrivValidatorKey, baseConfig.PrivValidatorState)
|
||||
baseConfig := DefaultBaseConfig()
|
||||
ensureFiles(t, rootDir, defaultDataDir, baseConfig.Genesis, baseConfig.PrivValidatorKey, baseConfig.PrivValidatorState)
|
||||
}
|
||||
|
||||
func assertValidConfig(t *testing.T, configFile string) {
|
||||
t.Helper()
|
||||
func checkConfig(configFile string) bool {
|
||||
var valid bool
|
||||
|
||||
// list of words we expect in the config
|
||||
var elems = []string{
|
||||
"moniker",
|
||||
"seeds",
|
||||
"proxy_app",
|
||||
"block_sync",
|
||||
"fast_sync",
|
||||
"create_empty_blocks",
|
||||
"peer",
|
||||
"timeout",
|
||||
@@ -79,6 +84,11 @@ func assertValidConfig(t *testing.T, configFile string) {
|
||||
"genesis",
|
||||
}
|
||||
for _, e := range elems {
|
||||
assert.Contains(t, configFile, e)
|
||||
if !strings.Contains(configFile, e) {
|
||||
valid = false
|
||||
} else {
|
||||
valid = true
|
||||
}
|
||||
}
|
||||
return valid
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Consensus
|
||||
|
||||
See the [consensus spec](https://github.com/tendermint/tendermint/tree/main/spec/consensus) for more information.
|
||||
See the [consensus spec](https://github.com/tendermint/tendermint/tree/v0.37.x/spec/consensus) and the [reactor consensus spec](https://github.com/tendermint/tendermint/tree/v0.37.x/spec/reactors/consensus) for more information.
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
evpool.SetLogger(logger.With("module", "evidence"))
|
||||
|
||||
// Make State
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool, blockStore)
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
|
||||
cs := NewState(thisConfig.Consensus, state, blockExec, blockStore, mempool, evpool)
|
||||
cs.SetLogger(cs.Logger)
|
||||
// set private validator
|
||||
@@ -165,16 +165,10 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
for i, peer := range peerList {
|
||||
if i < len(peerList)/2 {
|
||||
bcs.Logger.Info("Signed and pushed vote", "vote", prevote1, "peer", peer)
|
||||
peer.Send(p2p.Envelope{
|
||||
Message: MustMsgToProto(&VoteMessage{prevote1}),
|
||||
ChannelID: VoteChannel,
|
||||
})
|
||||
peer.Send(VoteChannel, MustEncode(&VoteMessage{prevote1}))
|
||||
} else {
|
||||
bcs.Logger.Info("Signed and pushed vote", "vote", prevote2, "peer", peer)
|
||||
peer.Send(p2p.Envelope{
|
||||
Message: MustMsgToProto(&VoteMessage{prevote2}),
|
||||
ChannelID: VoteChannel,
|
||||
})
|
||||
peer.Send(VoteChannel, MustEncode(&VoteMessage{prevote2}))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -527,10 +521,7 @@ func sendProposalAndParts(
|
||||
) {
|
||||
// proposal
|
||||
msg := &ProposalMessage{Proposal: proposal}
|
||||
peer.Send(p2p.Envelope{
|
||||
ChannelID: DataChannel,
|
||||
Message: MustMsgToProto(msg),
|
||||
})
|
||||
peer.Send(DataChannel, MustEncode(msg))
|
||||
|
||||
// parts
|
||||
for i := 0; i < int(parts.Total()); i++ {
|
||||
@@ -540,10 +531,7 @@ func sendProposalAndParts(
|
||||
Round: round, // This tells peer that this part applies to us.
|
||||
Part: part,
|
||||
}
|
||||
peer.Send(p2p.Envelope{
|
||||
ChannelID: DataChannel,
|
||||
Message: MustMsgToProto(msg),
|
||||
})
|
||||
peer.Send(DataChannel, MustEncode(msg))
|
||||
}
|
||||
|
||||
// votes
|
||||
@@ -551,14 +539,9 @@ func sendProposalAndParts(
|
||||
prevote, _ := cs.signVote(tmproto.PrevoteType, blockHash, parts.Header())
|
||||
precommit, _ := cs.signVote(tmproto.PrecommitType, blockHash, parts.Header())
|
||||
cs.mtx.Unlock()
|
||||
peer.Send(p2p.Envelope{
|
||||
ChannelID: VoteChannel,
|
||||
Message: MustMsgToProto(&VoteMessage{prevote}),
|
||||
})
|
||||
peer.Send(p2p.Envelope{
|
||||
ChannelID: VoteChannel,
|
||||
Message: MustMsgToProto(&VoteMessage{precommit}),
|
||||
})
|
||||
|
||||
peer.Send(VoteChannel, MustEncode(&VoteMessage{prevote}))
|
||||
peer.Send(VoteChannel, MustEncode(&VoteMessage{precommit}))
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
@@ -596,7 +579,7 @@ func (br *ByzantineReactor) AddPeer(peer p2p.Peer) {
|
||||
func (br *ByzantineReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
|
||||
br.reactor.RemovePeer(peer, reason)
|
||||
}
|
||||
func (br *ByzantineReactor) Receive(e p2p.Envelope) {
|
||||
br.reactor.Receive(e)
|
||||
func (br *ByzantineReactor) Receive(chID byte, peer p2p.Peer, msgBytes []byte) {
|
||||
br.reactor.Receive(chID, peer, msgBytes)
|
||||
}
|
||||
func (br *ByzantineReactor) InitPeer(peer p2p.Peer) p2p.Peer { return peer }
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
@@ -64,7 +63,7 @@ func ensureDir(dir string, mode os.FileMode) {
|
||||
}
|
||||
|
||||
func ResetConfig(name string) *cfg.Config {
|
||||
return test.ResetTestRoot(name)
|
||||
return cfg.ResetTestRoot(name)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
@@ -109,7 +108,7 @@ func (vs *validatorStub) signVote(
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: header},
|
||||
}
|
||||
v := vote.ToProto()
|
||||
if err := vs.PrivValidator.SignVote(test.DefaultTestChainID, v); err != nil {
|
||||
if err := vs.PrivValidator.SignVote(config.ChainID(), v); err != nil {
|
||||
return nil, fmt.Errorf("sign vote failed: %w", err)
|
||||
}
|
||||
|
||||
@@ -370,7 +369,7 @@ func subscribeToVoter(cs *State, addr []byte) <-chan tmpubsub.Message {
|
||||
// consensus states
|
||||
|
||||
func newState(state sm.State, pv types.PrivValidator, app abci.Application) *State {
|
||||
config := test.ResetTestRoot("consensus_state_test")
|
||||
config := cfg.ResetTestRoot("consensus_state_test")
|
||||
return newStateWithConfig(config, state, pv, app)
|
||||
}
|
||||
|
||||
@@ -439,7 +438,7 @@ func newStateWithConfigAndBlockStore(
|
||||
panic(err)
|
||||
}
|
||||
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool, blockStore)
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
|
||||
cs := NewState(thisConfig.Consensus, state, blockExec, blockStore, mempool, evpool)
|
||||
cs.SetLogger(log.TestingLogger().With("module", "consensus"))
|
||||
cs.SetPrivValidator(pv)
|
||||
@@ -869,7 +868,7 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
|
||||
return &types.GenesisDoc{
|
||||
GenesisTime: tmtime.Now(),
|
||||
InitialHeight: 1,
|
||||
ChainID: test.DefaultTestChainID,
|
||||
ChainID: config.ChainID(),
|
||||
Validators: validators,
|
||||
}, privValidators
|
||||
}
|
||||
|
||||
@@ -94,10 +94,7 @@ func invalidDoPrevoteFunc(t *testing.T, height int64, round int32, cs *State, sw
|
||||
peers := sw.Peers().List()
|
||||
for _, peer := range peers {
|
||||
cs.Logger.Info("Sending bad vote", "block", blockHash, "peer", peer)
|
||||
peer.Send(p2p.Envelope{
|
||||
Message: MustMsgToProto(&VoteMessage{precommit}),
|
||||
ChannelID: VoteChannel,
|
||||
})
|
||||
peer.Send(VoteChannel, MustEncode(&VoteMessage{precommit}))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -179,13 +179,13 @@ func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
|
||||
Subsystem: MetricsSubsystem,
|
||||
Name: "round_voting_power_percent",
|
||||
Help: "RoundVotingPowerPercent is the percentage of the total voting power received with a round. The value begins at 0 for each round and approaches 1.0 as additional voting power is observed. The metric is labeled by vote type.",
|
||||
}, append(labels, "vote_type")).With(labelsAndValues...),
|
||||
}, labels).With(labelsAndValues...),
|
||||
LateVotes: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: MetricsSubsystem,
|
||||
Name: "late_votes",
|
||||
Help: "LateVotes stores the number of votes that were received by this node that correspond to earlier heights and rounds than this node is currently in.",
|
||||
}, append(labels, "vote_type")).With(labelsAndValues...),
|
||||
}, labels).With(labelsAndValues...),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -108,12 +108,12 @@ type Metrics struct {
|
||||
// RoundVotingPowerPercent is the percentage of the total voting power received
|
||||
// with a round. The value begins at 0 for each round and approaches 1.0 as
|
||||
// additional voting power is observed. The metric is labeled by vote type.
|
||||
RoundVotingPowerPercent metrics.Gauge `metrics_labels:"vote_type"`
|
||||
RoundVotingPowerPercent metrics.Gauge
|
||||
|
||||
// LateVotes stores the number of votes that were received by this node that
|
||||
// correspond to earlier heights and rounds than this node is currently
|
||||
// in.
|
||||
LateVotes metrics.Counter `metrics_labels:"vote_type"`
|
||||
LateVotes metrics.Counter
|
||||
}
|
||||
|
||||
// RecordConsMetrics uses for recording the block related metrics during fast-sync.
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||
"github.com/tendermint/tendermint/libs/bits"
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// MsgToProto takes a consensus message type and returns the proto defined consensus message.
|
||||
// MsgToProto takes a consensus message type and returns the proto defined consensus message
|
||||
func MsgToProto(msg Message) (*tmcons.Message, error) {
|
||||
if msg == nil {
|
||||
return nil, errors.New("consensus: message is nil")
|
||||
@@ -143,14 +143,6 @@ func MsgToProto(msg Message) (*tmcons.Message, error) {
|
||||
return &pb, nil
|
||||
}
|
||||
|
||||
func MustMsgToProto(msg Message) *tmcons.Message {
|
||||
m, err := MsgToProto(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// MsgFromProto takes a consensus proto message and returns the native go type
|
||||
func MsgFromProto(msg *tmcons.Message) (Message, error) {
|
||||
if msg == nil {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||
"github.com/tendermint/tendermint/libs/bits"
|
||||
@@ -148,7 +148,6 @@ func (conR *Reactor) GetChannels() []*p2p.ChannelDescriptor {
|
||||
Priority: 6,
|
||||
SendQueueCapacity: 100,
|
||||
RecvMessageCapacity: maxMsgSize,
|
||||
MessageType: &tmcons.Message{},
|
||||
},
|
||||
{
|
||||
ID: DataChannel, // maybe split between gossiping current block and catchup stuff
|
||||
@@ -157,7 +156,6 @@ func (conR *Reactor) GetChannels() []*p2p.ChannelDescriptor {
|
||||
SendQueueCapacity: 100,
|
||||
RecvBufferCapacity: 50 * 4096,
|
||||
RecvMessageCapacity: maxMsgSize,
|
||||
MessageType: &tmcons.Message{},
|
||||
},
|
||||
{
|
||||
ID: VoteChannel,
|
||||
@@ -165,7 +163,6 @@ func (conR *Reactor) GetChannels() []*p2p.ChannelDescriptor {
|
||||
SendQueueCapacity: 100,
|
||||
RecvBufferCapacity: 100 * 100,
|
||||
RecvMessageCapacity: maxMsgSize,
|
||||
MessageType: &tmcons.Message{},
|
||||
},
|
||||
{
|
||||
ID: VoteSetBitsChannel,
|
||||
@@ -173,7 +170,6 @@ func (conR *Reactor) GetChannels() []*p2p.ChannelDescriptor {
|
||||
SendQueueCapacity: 2,
|
||||
RecvBufferCapacity: 1024,
|
||||
RecvMessageCapacity: maxMsgSize,
|
||||
MessageType: &tmcons.Message{},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -227,34 +223,34 @@ func (conR *Reactor) RemovePeer(peer p2p.Peer, reason interface{}) {
|
||||
// Peer state updates can happen in parallel, but processing of
|
||||
// proposals, block parts, and votes are ordered by the receiveRoutine
|
||||
// NOTE: blocks on consensus state for proposals, block parts, and votes
|
||||
func (conR *Reactor) Receive(e p2p.Envelope) {
|
||||
func (conR *Reactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
|
||||
if !conR.IsRunning() {
|
||||
conR.Logger.Debug("Receive", "src", e.Src, "chId", e.ChannelID)
|
||||
conR.Logger.Debug("Receive", "src", src, "chId", chID, "bytes", msgBytes)
|
||||
return
|
||||
}
|
||||
|
||||
msg, err := MsgFromProto(e.Message.(*tmcons.Message))
|
||||
msg, err := decodeMsg(msgBytes)
|
||||
if err != nil {
|
||||
conR.Logger.Error("Error decoding message", "src", e.Src, "chId", e.ChannelID, "err", err)
|
||||
conR.Switch.StopPeerForError(e.Src, err)
|
||||
conR.Logger.Error("Error decoding message", "src", src, "chId", chID, "err", err)
|
||||
conR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
conR.Logger.Error("Peer sent us invalid msg", "peer", e.Src, "msg", e.Message, "err", err)
|
||||
conR.Switch.StopPeerForError(e.Src, err)
|
||||
conR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
|
||||
conR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
|
||||
conR.Logger.Debug("Receive", "src", e.Src, "chId", e.ChannelID, "msg", msg)
|
||||
conR.Logger.Debug("Receive", "src", src, "chId", chID, "msg", msg)
|
||||
|
||||
// Get peer states
|
||||
ps, ok := e.Src.Get(types.PeerStateKey).(*PeerState)
|
||||
ps, ok := src.Get(types.PeerStateKey).(*PeerState)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Peer %v has no state", e.Src))
|
||||
panic(fmt.Sprintf("Peer %v has no state", src))
|
||||
}
|
||||
|
||||
switch e.ChannelID {
|
||||
switch chID {
|
||||
case StateChannel:
|
||||
switch msg := msg.(type) {
|
||||
case *NewRoundStepMessage:
|
||||
@@ -262,8 +258,8 @@ func (conR *Reactor) Receive(e p2p.Envelope) {
|
||||
initialHeight := conR.conS.state.InitialHeight
|
||||
conR.conS.mtx.Unlock()
|
||||
if err = msg.ValidateHeight(initialHeight); err != nil {
|
||||
conR.Logger.Error("Peer sent us invalid msg", "peer", e.Src, "msg", msg, "err", err)
|
||||
conR.Switch.StopPeerForError(e.Src, err)
|
||||
conR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
|
||||
conR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
ps.ApplyNewRoundStepMessage(msg)
|
||||
@@ -282,7 +278,7 @@ func (conR *Reactor) Receive(e p2p.Envelope) {
|
||||
// Peer claims to have a maj23 for some BlockID at H,R,S,
|
||||
err := votes.SetPeerMaj23(msg.Round, msg.Type, ps.peer.ID(), msg.BlockID)
|
||||
if err != nil {
|
||||
conR.Switch.StopPeerForError(e.Src, err)
|
||||
conR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
// Respond with a VoteSetBitsMessage showing which votes we have.
|
||||
@@ -296,16 +292,13 @@ func (conR *Reactor) Receive(e p2p.Envelope) {
|
||||
default:
|
||||
panic("Bad VoteSetBitsMessage field Type. Forgot to add a check in ValidateBasic?")
|
||||
}
|
||||
e.Src.TrySend(p2p.Envelope{
|
||||
ChannelID: VoteSetBitsChannel,
|
||||
Message: MustMsgToProto(&VoteSetBitsMessage{
|
||||
Height: msg.Height,
|
||||
Round: msg.Round,
|
||||
Type: msg.Type,
|
||||
BlockID: msg.BlockID,
|
||||
Votes: ourVotes,
|
||||
}),
|
||||
})
|
||||
src.TrySend(VoteSetBitsChannel, MustEncode(&VoteSetBitsMessage{
|
||||
Height: msg.Height,
|
||||
Round: msg.Round,
|
||||
Type: msg.Type,
|
||||
BlockID: msg.BlockID,
|
||||
Votes: ourVotes,
|
||||
}))
|
||||
default:
|
||||
conR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
|
||||
}
|
||||
@@ -318,13 +311,13 @@ func (conR *Reactor) Receive(e p2p.Envelope) {
|
||||
switch msg := msg.(type) {
|
||||
case *ProposalMessage:
|
||||
ps.SetHasProposal(msg.Proposal)
|
||||
conR.conS.peerMsgQueue <- msgInfo{msg, e.Src.ID()}
|
||||
conR.conS.peerMsgQueue <- msgInfo{msg, src.ID()}
|
||||
case *ProposalPOLMessage:
|
||||
ps.ApplyProposalPOLMessage(msg)
|
||||
case *BlockPartMessage:
|
||||
ps.SetHasProposalBlockPart(msg.Height, msg.Round, int(msg.Part.Index))
|
||||
conR.Metrics.BlockParts.With("peer_id", string(e.Src.ID())).Add(1)
|
||||
conR.conS.peerMsgQueue <- msgInfo{msg, e.Src.ID()}
|
||||
conR.Metrics.BlockParts.With("peer_id", string(src.ID())).Add(1)
|
||||
conR.conS.peerMsgQueue <- msgInfo{msg, src.ID()}
|
||||
default:
|
||||
conR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
|
||||
}
|
||||
@@ -344,7 +337,7 @@ func (conR *Reactor) Receive(e p2p.Envelope) {
|
||||
ps.EnsureVoteBitArrays(height-1, lastCommitSize)
|
||||
ps.SetHasVote(msg.Vote)
|
||||
|
||||
cs.peerMsgQueue <- msgInfo{msg, e.Src.ID()}
|
||||
cs.peerMsgQueue <- msgInfo{msg, src.ID()}
|
||||
|
||||
default:
|
||||
// don't punish (leave room for soft upgrades)
|
||||
@@ -383,7 +376,7 @@ func (conR *Reactor) Receive(e p2p.Envelope) {
|
||||
}
|
||||
|
||||
default:
|
||||
conR.Logger.Error(fmt.Sprintf("Unknown chId %X", e.ChannelID))
|
||||
conR.Logger.Error(fmt.Sprintf("Unknown chId %X", chID))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,10 +430,7 @@ func (conR *Reactor) unsubscribeFromBroadcastEvents() {
|
||||
|
||||
func (conR *Reactor) broadcastNewRoundStepMessage(rs *cstypes.RoundState) {
|
||||
nrsMsg := makeRoundStepMessage(rs)
|
||||
conR.Switch.NewBroadcast(p2p.Envelope{
|
||||
ChannelID: StateChannel,
|
||||
Message: MustMsgToProto(nrsMsg),
|
||||
})
|
||||
conR.Switch.Broadcast(StateChannel, MustEncode(nrsMsg))
|
||||
}
|
||||
|
||||
func (conR *Reactor) broadcastNewValidBlockMessage(rs *cstypes.RoundState) {
|
||||
@@ -451,11 +441,7 @@ func (conR *Reactor) broadcastNewValidBlockMessage(rs *cstypes.RoundState) {
|
||||
BlockParts: rs.ProposalBlockParts.BitArray(),
|
||||
IsCommit: rs.Step == cstypes.RoundStepCommit,
|
||||
}
|
||||
MsgToProto(csMsg)
|
||||
conR.Switch.NewBroadcast(p2p.Envelope{
|
||||
ChannelID: StateChannel,
|
||||
Message: MustMsgToProto(csMsg),
|
||||
})
|
||||
conR.Switch.Broadcast(StateChannel, MustEncode(csMsg))
|
||||
}
|
||||
|
||||
// Broadcasts HasVoteMessage to peers that care.
|
||||
@@ -466,10 +452,7 @@ func (conR *Reactor) broadcastHasVoteMessage(vote *types.Vote) {
|
||||
Type: vote.Type,
|
||||
Index: vote.ValidatorIndex,
|
||||
}
|
||||
conR.Switch.NewBroadcast(p2p.Envelope{
|
||||
ChannelID: StateChannel,
|
||||
Message: MustMsgToProto(msg),
|
||||
})
|
||||
conR.Switch.Broadcast(StateChannel, MustEncode(msg))
|
||||
/*
|
||||
// TODO: Make this broadcast more selective.
|
||||
for _, peer := range conR.Switch.Peers().List() {
|
||||
@@ -480,11 +463,7 @@ func (conR *Reactor) broadcastHasVoteMessage(vote *types.Vote) {
|
||||
prs := ps.GetRoundState()
|
||||
if prs.Height == vote.Height {
|
||||
// TODO: Also filter on round?
|
||||
e := p2p.Envelope{
|
||||
ChannelID: StateChannel, struct{ ConsensusMessage }{msg},
|
||||
Message: p,
|
||||
}
|
||||
peer.TrySend(e)
|
||||
peer.TrySend(StateChannel, struct{ ConsensusMessage }{msg})
|
||||
} else {
|
||||
// Height doesn't match
|
||||
// TODO: check a field, maybe CatchupCommitRound?
|
||||
@@ -508,10 +487,7 @@ func makeRoundStepMessage(rs *cstypes.RoundState) (nrsMsg *NewRoundStepMessage)
|
||||
func (conR *Reactor) sendNewRoundStepMessage(peer p2p.Peer) {
|
||||
rs := conR.getRoundState()
|
||||
nrsMsg := makeRoundStepMessage(rs)
|
||||
peer.Send(p2p.Envelope{
|
||||
ChannelID: StateChannel,
|
||||
Message: MustMsgToProto(nrsMsg),
|
||||
})
|
||||
peer.Send(StateChannel, MustEncode(nrsMsg))
|
||||
}
|
||||
|
||||
func (conR *Reactor) updateRoundStateRoutine() {
|
||||
@@ -556,10 +532,7 @@ OUTER_LOOP:
|
||||
Part: part,
|
||||
}
|
||||
logger.Debug("Sending block part", "height", prs.Height, "round", prs.Round)
|
||||
if peer.Send(p2p.Envelope{
|
||||
ChannelID: DataChannel,
|
||||
Message: MustMsgToProto(msg),
|
||||
}) {
|
||||
if peer.Send(DataChannel, MustEncode(msg)) {
|
||||
ps.SetHasProposalBlockPart(prs.Height, prs.Round, index)
|
||||
}
|
||||
continue OUTER_LOOP
|
||||
@@ -607,10 +580,7 @@ OUTER_LOOP:
|
||||
{
|
||||
msg := &ProposalMessage{Proposal: rs.Proposal}
|
||||
logger.Debug("Sending proposal", "height", prs.Height, "round", prs.Round)
|
||||
if peer.Send(p2p.Envelope{
|
||||
ChannelID: DataChannel,
|
||||
Message: MustMsgToProto(msg),
|
||||
}) {
|
||||
if peer.Send(DataChannel, MustEncode(msg)) {
|
||||
// NOTE[ZM]: A peer might have received different proposal msg so this Proposal msg will be rejected!
|
||||
ps.SetHasProposal(rs.Proposal)
|
||||
}
|
||||
@@ -626,10 +596,7 @@ OUTER_LOOP:
|
||||
ProposalPOL: rs.Votes.Prevotes(rs.Proposal.POLRound).BitArray(),
|
||||
}
|
||||
logger.Debug("Sending POL", "height", prs.Height, "round", prs.Round)
|
||||
peer.Send(p2p.Envelope{
|
||||
ChannelID: DataChannel,
|
||||
Message: MustMsgToProto(msg),
|
||||
})
|
||||
peer.Send(DataChannel, MustEncode(msg))
|
||||
}
|
||||
continue OUTER_LOOP
|
||||
}
|
||||
@@ -672,10 +639,7 @@ func (conR *Reactor) gossipDataForCatchup(logger log.Logger, rs *cstypes.RoundSt
|
||||
Part: part,
|
||||
}
|
||||
logger.Debug("Sending block part for catchup", "round", prs.Round, "index", index)
|
||||
if peer.Send(p2p.Envelope{
|
||||
ChannelID: DataChannel,
|
||||
Message: MustMsgToProto(msg),
|
||||
}) {
|
||||
if peer.Send(DataChannel, MustEncode(msg)) {
|
||||
ps.SetHasProposalBlockPart(prs.Height, prs.Round, index)
|
||||
} else {
|
||||
logger.Debug("Sending block part for catchup failed")
|
||||
@@ -834,16 +798,12 @@ OUTER_LOOP:
|
||||
prs := ps.GetRoundState()
|
||||
if rs.Height == prs.Height {
|
||||
if maj23, ok := rs.Votes.Prevotes(prs.Round).TwoThirdsMajority(); ok {
|
||||
|
||||
peer.TrySend(p2p.Envelope{
|
||||
ChannelID: StateChannel,
|
||||
Message: MustMsgToProto(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.Round,
|
||||
Type: tmproto.PrevoteType,
|
||||
BlockID: maj23,
|
||||
}),
|
||||
})
|
||||
peer.TrySend(StateChannel, MustEncode(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.Round,
|
||||
Type: tmproto.PrevoteType,
|
||||
BlockID: maj23,
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||
}
|
||||
}
|
||||
@@ -855,16 +815,12 @@ OUTER_LOOP:
|
||||
prs := ps.GetRoundState()
|
||||
if rs.Height == prs.Height {
|
||||
if maj23, ok := rs.Votes.Precommits(prs.Round).TwoThirdsMajority(); ok {
|
||||
|
||||
peer.TrySend(p2p.Envelope{
|
||||
ChannelID: StateChannel,
|
||||
Message: MustMsgToProto(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.Round,
|
||||
Type: tmproto.PrecommitType,
|
||||
BlockID: maj23,
|
||||
}),
|
||||
})
|
||||
peer.TrySend(StateChannel, MustEncode(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.Round,
|
||||
Type: tmproto.PrecommitType,
|
||||
BlockID: maj23,
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||
}
|
||||
}
|
||||
@@ -876,16 +832,12 @@ OUTER_LOOP:
|
||||
prs := ps.GetRoundState()
|
||||
if rs.Height == prs.Height && prs.ProposalPOLRound >= 0 {
|
||||
if maj23, ok := rs.Votes.Prevotes(prs.ProposalPOLRound).TwoThirdsMajority(); ok {
|
||||
|
||||
peer.TrySend(p2p.Envelope{
|
||||
ChannelID: StateChannel,
|
||||
Message: MustMsgToProto(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.ProposalPOLRound,
|
||||
Type: tmproto.PrevoteType,
|
||||
BlockID: maj23,
|
||||
}),
|
||||
})
|
||||
peer.TrySend(StateChannel, MustEncode(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.ProposalPOLRound,
|
||||
Type: tmproto.PrevoteType,
|
||||
BlockID: maj23,
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||
}
|
||||
}
|
||||
@@ -900,15 +852,12 @@ OUTER_LOOP:
|
||||
if prs.CatchupCommitRound != -1 && prs.Height > 0 && prs.Height <= conR.conS.blockStore.Height() &&
|
||||
prs.Height >= conR.conS.blockStore.Base() {
|
||||
if commit := conR.conS.LoadCommit(prs.Height); commit != nil {
|
||||
peer.TrySend(p2p.Envelope{
|
||||
ChannelID: StateChannel,
|
||||
Message: MustMsgToProto(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: commit.Round,
|
||||
Type: tmproto.PrecommitType,
|
||||
BlockID: commit.BlockID,
|
||||
}),
|
||||
})
|
||||
peer.TrySend(StateChannel, MustEncode(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: commit.Round,
|
||||
Type: tmproto.PrecommitType,
|
||||
BlockID: commit.BlockID,
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||
}
|
||||
}
|
||||
@@ -1124,10 +1073,7 @@ func (ps *PeerState) PickSendVote(votes types.VoteSetReader) bool {
|
||||
if vote, ok := ps.PickVoteToSend(votes); ok {
|
||||
msg := &VoteMessage{vote}
|
||||
ps.logger.Debug("Sending vote message", "ps", ps, "vote", vote)
|
||||
if ps.peer.Send(p2p.Envelope{
|
||||
ChannelID: VoteChannel,
|
||||
Message: MustMsgToProto(msg),
|
||||
}) {
|
||||
if ps.peer.Send(VoteChannel, MustEncode(msg)) {
|
||||
ps.SetHasVote(vote)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ func TestReactorWithEvidence(t *testing.T) {
|
||||
// mock the evidence pool
|
||||
// everyone includes evidence of another double signing
|
||||
vIdx := (i + 1) % nValidators
|
||||
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultTestTime, privVals[vIdx], genDoc.ChainID)
|
||||
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultTestTime, privVals[vIdx], config.ChainID())
|
||||
require.NoError(t, err)
|
||||
evpool := &statemocks.EvidencePool{}
|
||||
evpool.On("CheckEvidence", mock.AnythingOfType("types.EvidenceList")).Return(nil)
|
||||
@@ -201,7 +201,7 @@ func TestReactorWithEvidence(t *testing.T) {
|
||||
evpool2 := sm.EmptyEvidencePool{}
|
||||
|
||||
// Make State
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool, blockStore)
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
|
||||
cs := NewState(thisConfig.Consensus, state, blockExec, blockStore, mempool, evpool2)
|
||||
cs.SetLogger(log.TestingLogger().With("module", "consensus"))
|
||||
cs.SetPrivValidator(pv)
|
||||
@@ -297,12 +297,6 @@ func TestReactorReceivePanicsIfInitPeerHasntBeenCalledYet(t *testing.T) {
|
||||
// simulate switch calling Receive before AddPeer
|
||||
assert.Panics(t, func() {
|
||||
reactor.Receive(StateChannel, peer, msg)
|
||||
reactor.NewReceive(p2p.Envelope{
|
||||
ChannelID: StateChannel,
|
||||
Src: peer,
|
||||
Message: MustMsgToProto(&HasVoteMessage{Height: 1,
|
||||
Round: 1, Index: 1, Type: tmproto.PrevoteType}),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -496,11 +496,11 @@ func (h *Handshaker) replayBlock(state sm.State, height int64, proxyApp proxy.Ap
|
||||
|
||||
// Use stubs for both mempool and evidence pool since no transactions nor
|
||||
// evidence are needed here - block already exists.
|
||||
blockExec := sm.NewBlockExecutor(h.stateStore, h.logger, proxyApp, emptyMempool{}, sm.EmptyEvidencePool{}, h.store)
|
||||
blockExec := sm.NewBlockExecutor(h.stateStore, h.logger, proxyApp, emptyMempool{}, sm.EmptyEvidencePool{})
|
||||
blockExec.SetEventBus(h.eventBus)
|
||||
|
||||
var err error
|
||||
state, err = blockExec.ApplyBlock(state, meta.BlockID, block)
|
||||
state, _, err = blockExec.ApplyBlock(state, meta.BlockID, block)
|
||||
if err != nil {
|
||||
return sm.State{}, err
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ func newConsensusStateForReplay(config cfg.BaseConfig, csConfig *cfg.ConsensusCo
|
||||
}
|
||||
|
||||
mempool, evpool := emptyMempool{}, sm.EmptyEvidencePool{}
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool, blockStore)
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
|
||||
|
||||
consensusState := NewState(csConfig, state.Copy(), blockExec,
|
||||
blockStore, mempool, evpool)
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
@@ -373,7 +373,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
|
||||
|
||||
proposal := types.NewProposal(vss[1].Height, round, -1, blockID)
|
||||
p := proposal.ToProto()
|
||||
if err := vss[1].SignProposal(genDoc.ChainID, p); err != nil {
|
||||
if err := vss[1].SignProposal(config.ChainID(), p); err != nil {
|
||||
t.Fatal("failed to sign bad proposal", err)
|
||||
}
|
||||
proposal.Signature = p.Signature
|
||||
@@ -405,7 +405,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
|
||||
|
||||
proposal = types.NewProposal(vss[2].Height, round, -1, blockID)
|
||||
p = proposal.ToProto()
|
||||
if err := vss[2].SignProposal(genDoc.ChainID, p); err != nil {
|
||||
if err := vss[2].SignProposal(config.ChainID(), p); err != nil {
|
||||
t.Fatal("failed to sign bad proposal", err)
|
||||
}
|
||||
proposal.Signature = p.Signature
|
||||
@@ -464,7 +464,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
|
||||
|
||||
proposal = types.NewProposal(vss[3].Height, round, -1, blockID)
|
||||
p = proposal.ToProto()
|
||||
if err := vss[3].SignProposal(genDoc.ChainID, p); err != nil {
|
||||
if err := vss[3].SignProposal(config.ChainID(), p); err != nil {
|
||||
t.Fatal("failed to sign bad proposal", err)
|
||||
}
|
||||
proposal.Signature = p.Signature
|
||||
@@ -525,7 +525,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
|
||||
selfIndex = valIndexFn(0)
|
||||
proposal = types.NewProposal(vss[1].Height, round, -1, blockID)
|
||||
p = proposal.ToProto()
|
||||
if err := vss[1].SignProposal(genDoc.ChainID, p); err != nil {
|
||||
if err := vss[1].SignProposal(config.ChainID(), p); err != nil {
|
||||
t.Fatal("failed to sign bad proposal", err)
|
||||
}
|
||||
proposal.Signature = p.Signature
|
||||
@@ -711,7 +711,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(t, config, stateStore, state, chain, nBlocks, mode, store)
|
||||
state = buildTMStateFromChain(t, config, stateStore, state, chain, nBlocks, mode)
|
||||
latestAppHash := state.AppHash
|
||||
|
||||
// make a new client creator
|
||||
@@ -729,13 +729,13 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin
|
||||
})
|
||||
err := stateStore.Save(genesisState)
|
||||
require.NoError(t, err)
|
||||
buildAppStateFromChain(t, proxyApp, stateStore, genesisState, chain, nBlocks, mode, store)
|
||||
buildAppStateFromChain(t, proxyApp, stateStore, genesisState, chain, nBlocks, mode)
|
||||
}
|
||||
|
||||
// Prune block store if requested
|
||||
expectError := false
|
||||
if mode == 3 {
|
||||
pruned, _, err := store.PruneBlocks(2, state)
|
||||
pruned, err := store.PruneBlocks(2)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, pruned)
|
||||
expectError = int64(nBlocks) < 2
|
||||
@@ -789,20 +789,20 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin
|
||||
}
|
||||
}
|
||||
|
||||
func applyBlock(t *testing.T, stateStore sm.Store, st sm.State, blk *types.Block, proxyApp proxy.AppConns, bs *mockBlockStore) 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, bs)
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
|
||||
|
||||
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)
|
||||
newState, _, err := blockExec.ApplyBlock(st, blkID, blk)
|
||||
require.NoError(t, err)
|
||||
return newState
|
||||
}
|
||||
|
||||
func buildAppStateFromChain(t *testing.T, proxyApp proxy.AppConns, stateStore sm.Store,
|
||||
state sm.State, chain []*types.Block, nBlocks int, mode uint, blockStore *mockBlockStore) {
|
||||
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 {
|
||||
panic(err)
|
||||
@@ -823,18 +823,18 @@ func buildAppStateFromChain(t *testing.T, proxyApp proxy.AppConns, stateStore sm
|
||||
case 0:
|
||||
for i := 0; i < nBlocks; i++ {
|
||||
block := chain[i]
|
||||
state = applyBlock(t, stateStore, state, block, proxyApp, blockStore)
|
||||
state = applyBlock(t, stateStore, state, block, proxyApp)
|
||||
}
|
||||
case 1, 2, 3:
|
||||
for i := 0; i < nBlocks-1; i++ {
|
||||
block := chain[i]
|
||||
state = applyBlock(t, stateStore, state, block, proxyApp, blockStore)
|
||||
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(t, stateStore, state, chain[nBlocks-1], proxyApp, blockStore)
|
||||
state = applyBlock(t, stateStore, state, chain[nBlocks-1], proxyApp)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown mode %v", mode))
|
||||
@@ -849,8 +849,7 @@ func buildTMStateFromChain(
|
||||
state sm.State,
|
||||
chain []*types.Block,
|
||||
nBlocks int,
|
||||
mode uint,
|
||||
blockStore *mockBlockStore) sm.State {
|
||||
mode uint) sm.State {
|
||||
// run the whole chain against this client to build up the tendermint state
|
||||
clientCreator := proxy.NewLocalClientCreator(
|
||||
kvstore.NewPersistentKVStoreApplication(
|
||||
@@ -875,19 +874,19 @@ func buildTMStateFromChain(
|
||||
case 0:
|
||||
// sync right up
|
||||
for _, block := range chain {
|
||||
state = applyBlock(t, stateStore, state, block, proxyApp, blockStore)
|
||||
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(t, stateStore, state, block, proxyApp, blockStore)
|
||||
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(t, stateStore, state, chain[len(chain)-1], proxyApp, blockStore)
|
||||
applyBlock(t, stateStore, state, chain[len(chain)-1], proxyApp)
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown mode %v", mode))
|
||||
}
|
||||
@@ -1165,7 +1164,6 @@ func (bs *mockBlockStore) LoadBlock(height int64) *types.Block { return bs.chain
|
||||
func (bs *mockBlockStore) LoadBlockByHash(hash []byte) *types.Block {
|
||||
return bs.chain[int64(len(bs.chain))-1]
|
||||
}
|
||||
func (bs *mockBlockStore) LoadBlockMetaByHash(hash []byte) *types.BlockMeta { return nil }
|
||||
func (bs *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
|
||||
block := bs.chain[height-1]
|
||||
bps, err := block.MakePartSet(types.BlockPartSizeBytes)
|
||||
@@ -1185,8 +1183,7 @@ func (bs *mockBlockStore) LoadSeenCommit(height int64) *types.Commit {
|
||||
return bs.commits[height-1]
|
||||
}
|
||||
|
||||
func (bs *mockBlockStore) PruneBlocks(height int64, state sm.State) (uint64, int64, error) {
|
||||
evidencePoint := height
|
||||
func (bs *mockBlockStore) PruneBlocks(height int64) (uint64, error) {
|
||||
pruned := uint64(0)
|
||||
for i := int64(0); i < height-1; i++ {
|
||||
bs.chain[i] = nil
|
||||
@@ -1194,11 +1191,9 @@ func (bs *mockBlockStore) PruneBlocks(height int64, state sm.State) (uint64, int
|
||||
pruned++
|
||||
}
|
||||
bs.base = height
|
||||
return pruned, evidencePoint, nil
|
||||
return pruned, nil
|
||||
}
|
||||
|
||||
func (bs *mockBlockStore) DeleteLatestBlock() error { return nil }
|
||||
|
||||
//---------------------------------------
|
||||
// Test handshake/init chain
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||
@@ -468,7 +468,6 @@ func (cs *State) AddVote(vote *types.Vote, peerID p2p.ID) (added bool, err error
|
||||
|
||||
// SetProposal inputs a proposal.
|
||||
func (cs *State) SetProposal(proposal *types.Proposal, peerID p2p.ID) error {
|
||||
|
||||
if peerID == "" {
|
||||
cs.internalMsgQueue <- msgInfo{&ProposalMessage{proposal}, ""}
|
||||
} else {
|
||||
@@ -481,7 +480,6 @@ func (cs *State) SetProposal(proposal *types.Proposal, peerID p2p.ID) error {
|
||||
|
||||
// AddProposalBlockPart inputs a part of the proposal block.
|
||||
func (cs *State) AddProposalBlockPart(height int64, round int32, part *types.Part, peerID p2p.ID) error {
|
||||
|
||||
if peerID == "" {
|
||||
cs.internalMsgQueue <- msgInfo{&BlockPartMessage{height, round, part}, ""}
|
||||
} else {
|
||||
@@ -499,7 +497,6 @@ func (cs *State) SetProposalAndBlock(
|
||||
parts *types.PartSet,
|
||||
peerID p2p.ID,
|
||||
) error {
|
||||
|
||||
if err := cs.SetProposal(proposal, peerID); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -945,7 +942,6 @@ func (cs *State) handleTimeout(ti timeoutInfo, rs cstypes.RoundState) {
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid timeout step: %v", ti.Step))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (cs *State) handleTxsAvailable() {
|
||||
@@ -1196,7 +1192,6 @@ func (cs *State) isProposalComplete() bool {
|
||||
}
|
||||
// if this is false the proposer is lying or we haven't received the POL yet
|
||||
return cs.Votes.Prevotes(cs.Proposal.POLRound).HasTwoThirdsMajority()
|
||||
|
||||
}
|
||||
|
||||
// Create the next block to propose and return it. Returns nil block upon error.
|
||||
@@ -1694,7 +1689,12 @@ func (cs *State) finalizeCommit(height int64) {
|
||||
|
||||
// Execute and commit the block, update and save the state, and update the mempool.
|
||||
// NOTE The block.AppHash wont reflect these txs until the next block.
|
||||
stateCopy, err := cs.blockExec.ApplyBlock(
|
||||
var (
|
||||
err error
|
||||
retainHeight int64
|
||||
)
|
||||
|
||||
stateCopy, retainHeight, err = cs.blockExec.ApplyBlock(
|
||||
stateCopy,
|
||||
types.BlockID{
|
||||
Hash: block.Hash(),
|
||||
@@ -1709,6 +1709,16 @@ func (cs *State) finalizeCommit(height int64) {
|
||||
|
||||
fail.Fail() // XXX
|
||||
|
||||
// Prune old heights, if requested by ABCI app.
|
||||
if retainHeight > 0 {
|
||||
pruned, err := cs.pruneBlocks(retainHeight)
|
||||
if err != nil {
|
||||
logger.Error("failed to prune blocks", "retain_height", retainHeight, "err", err)
|
||||
} else {
|
||||
logger.Debug("pruned blocks", "pruned", pruned, "retain_height", retainHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// must be called before we update state
|
||||
cs.recordMetrics(height, block)
|
||||
|
||||
@@ -1732,6 +1742,22 @@ func (cs *State) finalizeCommit(height int64) {
|
||||
// * cs.StartTime is set to when we will start round0.
|
||||
}
|
||||
|
||||
func (cs *State) pruneBlocks(retainHeight int64) (uint64, error) {
|
||||
base := cs.blockStore.Base()
|
||||
if retainHeight <= base {
|
||||
return 0, nil
|
||||
}
|
||||
pruned, err := cs.blockStore.PruneBlocks(retainHeight)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to prune block store: %w", err)
|
||||
}
|
||||
err = cs.blockExec.Store().PruneStates(base, retainHeight)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to prune state database: %w", err)
|
||||
}
|
||||
return pruned, nil
|
||||
}
|
||||
|
||||
func (cs *State) recordMetrics(height int64, block *types.Block) {
|
||||
cs.metrics.Validators.Set(float64(cs.Validators.Size()))
|
||||
cs.metrics.ValidatorsPower.Set(float64(cs.Validators.TotalVotingPower()))
|
||||
@@ -1910,7 +1936,7 @@ func (cs *State) addProposalBlockPart(msg *BlockPartMessage, peerID p2p.ID) (add
|
||||
return added, err
|
||||
}
|
||||
|
||||
var pbb = new(tmproto.Block)
|
||||
pbb := new(tmproto.Block)
|
||||
err = proto.Unmarshal(bz, pbb)
|
||||
if err != nil {
|
||||
return added, err
|
||||
@@ -2243,10 +2269,10 @@ func (cs *State) voteTime() time.Time {
|
||||
// Minimum time increment between blocks
|
||||
const timeIota = time.Millisecond
|
||||
// TODO: We should remove next line in case we don't vote for v in case cs.ProposalBlock == nil,
|
||||
// even if cs.LockedBlock != nil. See https://github.com/tendermint/tendermint/tree/main/spec/.
|
||||
// even if cs.LockedBlock != nil. See https://github.com/tendermint/tendermint/tree/v0.37.x/spec/.
|
||||
if cs.LockedBlock != nil {
|
||||
// See the BFT time spec
|
||||
// https://github.com/tendermint/tendermint/blob/main/spec/consensus/bft-time.md
|
||||
// https://github.com/tendermint/tendermint/blob/v0.37.x/spec/consensus/bft-time.md
|
||||
minVoteTime = cs.LockedBlock.Time.Add(timeIota)
|
||||
} else if cs.ProposalBlock != nil {
|
||||
minVoteTime = cs.ProposalBlock.Time.Add(timeIota)
|
||||
|
||||
@@ -214,7 +214,7 @@ func TestStateBadProposal(t *testing.T) {
|
||||
blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()}
|
||||
proposal := types.NewProposal(vs2.Height, round, -1, blockID)
|
||||
p := proposal.ToProto()
|
||||
if err := vs2.SignProposal(cs1.state.ChainID, p); err != nil {
|
||||
if err := vs2.SignProposal(config.ChainID(), p); err != nil {
|
||||
t.Fatal("failed to sign bad proposal", err)
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ func TestStateOversizedBlock(t *testing.T) {
|
||||
blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()}
|
||||
proposal := types.NewProposal(height, round, -1, blockID)
|
||||
p := proposal.ToProto()
|
||||
if err := vs2.SignProposal(cs1.state.ChainID, p); err != nil {
|
||||
if err := vs2.SignProposal(config.ChainID(), p); err != nil {
|
||||
t.Fatal("failed to sign bad proposal", err)
|
||||
}
|
||||
proposal.Signature = p.Signature
|
||||
@@ -1132,7 +1132,7 @@ func TestStateLockPOLSafety2(t *testing.T) {
|
||||
// in round 2 we see the polkad block from round 0
|
||||
newProp := types.NewProposal(height, round, 0, propBlockID0)
|
||||
p := newProp.ToProto()
|
||||
if err := vs3.SignProposal(cs1.state.ChainID, p); err != nil {
|
||||
if err := vs3.SignProposal(config.ChainID(), p); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
@@ -17,7 +16,7 @@ import (
|
||||
var config *cfg.Config // NOTE: must be reset for each _test.go file
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
config = test.ResetTestRoot("consensus_height_vote_set_test")
|
||||
config = cfg.ResetTestRoot("consensus_height_vote_set_test")
|
||||
code := m.Run()
|
||||
os.RemoveAll(config.RootDir)
|
||||
os.Exit(code)
|
||||
@@ -26,7 +25,7 @@ func TestMain(m *testing.M) {
|
||||
func TestPeerCatchupRounds(t *testing.T) {
|
||||
valSet, privVals := types.RandValidatorSet(10, 1)
|
||||
|
||||
hvs := NewHeightVoteSet(test.DefaultTestChainID, 1, valSet)
|
||||
hvs := NewHeightVoteSet(config.ChainID(), 1, valSet)
|
||||
|
||||
vote999_0 := makeVoteHR(t, 1, 0, 999, privVals)
|
||||
added, err := hvs.AddVote(vote999_0, "peer1")
|
||||
@@ -74,9 +73,10 @@ func makeVoteHR(t *testing.T, height int64, valIndex, round int32, privVals []ty
|
||||
Type: tmproto.PrecommitType,
|
||||
BlockID: types.BlockID{Hash: randBytes, PartSetHeader: types.PartSetHeader{}},
|
||||
}
|
||||
chainID := config.ChainID()
|
||||
|
||||
v := vote.ToProto()
|
||||
err = privVal.SignVote(test.DefaultTestChainID, v)
|
||||
err = privVal.SignVote(chainID, v)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error signing vote: %v", err))
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
auto "github.com/tendermint/tendermint/libs/autofile"
|
||||
tmjson "github.com/tendermint/tendermint/libs/json"
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
@@ -85,7 +84,7 @@ func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) {
|
||||
})
|
||||
mempool := emptyMempool{}
|
||||
evpool := sm.EmptyEvidencePool{}
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool, blockStore)
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
|
||||
consensusState := NewState(config.Consensus, state.Copy(), blockExec, blockStore, mempool, evpool)
|
||||
consensusState.SetLogger(logger)
|
||||
consensusState.SetEventBus(eventBus)
|
||||
@@ -150,7 +149,7 @@ func makeAddrs() (string, string, string) {
|
||||
|
||||
// getConfig returns a config for test cases
|
||||
func getConfig(t *testing.T) *cfg.Config {
|
||||
c := test.ResetTestRoot(t.Name())
|
||||
c := cfg.ResetTestRoot(t.Name())
|
||||
|
||||
// and we use random ports to run in parallel
|
||||
tm, rpc, grpc := makeAddrs()
|
||||
|
||||
@@ -12,7 +12,7 @@ For any specific algorithm, use its specific module e.g.
|
||||
|
||||
## Binary encoding
|
||||
|
||||
For Binary encoding, please refer to the [Tendermint encoding specification](https://github.com/tendermint/tendermint/blob/main/spec/core/encoding.md).
|
||||
For Binary encoding, please refer to the [Tendermint encoding specification](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/core/encoding.md).
|
||||
|
||||
## JSON Encoding
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package batch
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/sr25519"
|
||||
)
|
||||
|
||||
// CreateBatchVerifier checks if a key type implements the batch verifier interface.
|
||||
// Currently only ed25519 & sr25519 supports batch verification.
|
||||
func CreateBatchVerifier(pk crypto.PubKey) (crypto.BatchVerifier, bool) {
|
||||
switch pk.Type() {
|
||||
case ed25519.KeyType:
|
||||
return ed25519.NewBatchVerifier(), true
|
||||
case sr25519.KeyType:
|
||||
return sr25519.NewBatchVerifier(), true
|
||||
}
|
||||
|
||||
// case where the key does not support batch verification
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// SupportsBatchVerifier checks if a key type implements the batch verifier
|
||||
// interface.
|
||||
func SupportsBatchVerifier(pk crypto.PubKey) bool {
|
||||
switch pk.Type() {
|
||||
case ed25519.KeyType, sr25519.KeyType:
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -40,15 +40,3 @@ type Symmetric interface {
|
||||
Encrypt(plaintext []byte, secret []byte) (ciphertext []byte)
|
||||
Decrypt(ciphertext []byte, secret []byte) (plaintext []byte, err error)
|
||||
}
|
||||
|
||||
// If a new key type implements batch verification,
|
||||
// the key type must be registered in github.com/tendermint/tendermint/crypto/batch
|
||||
type BatchVerifier interface {
|
||||
// Add appends an entry into the BatchVerifier.
|
||||
Add(key PubKey, message, signature []byte) error
|
||||
// Verify verifies all the entries in the BatchVerifier, and returns
|
||||
// if every signature in the batch is valid, and a vector of bools
|
||||
// indicating the verification status of each signature (in the order
|
||||
// that signatures were added to the batch).
|
||||
Verify() (bool, []bool)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package ed25519
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/internal/benchmarking"
|
||||
)
|
||||
@@ -27,42 +24,3 @@ func BenchmarkVerification(b *testing.B) {
|
||||
priv := GenPrivKey()
|
||||
benchmarking.BenchmarkVerification(b, priv)
|
||||
}
|
||||
|
||||
func BenchmarkVerifyBatch(b *testing.B) {
|
||||
msg := []byte("BatchVerifyTest")
|
||||
|
||||
for _, sigsCount := range []int{1, 8, 64, 1024} {
|
||||
sigsCount := sigsCount
|
||||
b.Run(fmt.Sprintf("sig-count-%d", sigsCount), func(b *testing.B) {
|
||||
// Pre-generate all of the keys, and signatures, but do not
|
||||
// benchmark key-generation and signing.
|
||||
pubs := make([]crypto.PubKey, 0, sigsCount)
|
||||
sigs := make([][]byte, 0, sigsCount)
|
||||
for i := 0; i < sigsCount; i++ {
|
||||
priv := GenPrivKey()
|
||||
sig, _ := priv.Sign(msg)
|
||||
pubs = append(pubs, priv.PubKey().(PubKey))
|
||||
sigs = append(sigs, sig)
|
||||
}
|
||||
b.ResetTimer()
|
||||
|
||||
b.ReportAllocs()
|
||||
// NOTE: dividing by n so that metrics are per-signature
|
||||
for i := 0; i < b.N/sigsCount; i++ {
|
||||
// The benchmark could just benchmark the Verify()
|
||||
// routine, but there is non-trivial overhead associated
|
||||
// with BatchVerifier.Add(), which should be included
|
||||
// in the benchmark.
|
||||
v := NewBatchVerifier()
|
||||
for i := 0; i < sigsCount; i++ {
|
||||
err := v.Add(pubs[i], msg, sigs[i])
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
if ok, _ := v.Verify(); !ok {
|
||||
b.Fatal("signature set failed batch verification")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,10 @@ package ed25519
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/oasisprotocol/curve25519-voi/primitives/ed25519"
|
||||
"github.com/oasisprotocol/curve25519-voi/primitives/ed25519/extra/cache"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
@@ -17,19 +15,7 @@ import (
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
var (
|
||||
_ crypto.PrivKey = PrivKey{}
|
||||
_ crypto.BatchVerifier = &BatchVerifier{}
|
||||
|
||||
// curve25519-voi's Ed25519 implementation supports configurable
|
||||
// verification behavior, and tendermint uses the ZIP-215 verification
|
||||
// semantics.
|
||||
verifyOptions = &ed25519.Options{
|
||||
Verify: ed25519.VerifyOptionsZIP_215,
|
||||
}
|
||||
|
||||
cachingVerifier = cache.NewVerifier(cache.NewLRUCache(cacheSize))
|
||||
)
|
||||
var _ crypto.PrivKey = PrivKey{}
|
||||
|
||||
const (
|
||||
PrivKeyName = "tendermint/PrivKeyEd25519"
|
||||
@@ -46,14 +32,6 @@ const (
|
||||
SeedSize = 32
|
||||
|
||||
KeyType = "ed25519"
|
||||
|
||||
// cacheSize is the number of public keys that will be cached in
|
||||
// an expanded format for repeated signature verification.
|
||||
//
|
||||
// TODO/perf: Either this should exclude single verification, or be
|
||||
// tuned to `> validatorSize + maxTxnsPerBlock` to avoid cache
|
||||
// thrashing.
|
||||
cacheSize = 4096
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -127,12 +105,14 @@ func GenPrivKey() PrivKey {
|
||||
|
||||
// genPrivKey generates a new ed25519 private key using the provided reader.
|
||||
func genPrivKey(rand io.Reader) PrivKey {
|
||||
_, priv, err := ed25519.GenerateKey(rand)
|
||||
seed := make([]byte, SeedSize)
|
||||
|
||||
_, err := io.ReadFull(rand, seed)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return PrivKey(priv)
|
||||
return PrivKey(ed25519.NewKeyFromSeed(seed))
|
||||
}
|
||||
|
||||
// GenPrivKeyFromSecret hashes the secret with SHA2, and uses
|
||||
@@ -149,7 +129,7 @@ func GenPrivKeyFromSecret(secret []byte) PrivKey {
|
||||
|
||||
var _ crypto.PubKey = PubKey{}
|
||||
|
||||
// PubKey implements crypto.PubKey for the Ed25519 signature scheme.
|
||||
// PubKeyEd25519 implements crypto.PubKey for the Ed25519 signature scheme.
|
||||
type PubKey []byte
|
||||
|
||||
// Address is the SHA256-20 of the raw pubkey bytes.
|
||||
@@ -171,7 +151,7 @@ func (pubKey PubKey) VerifySignature(msg []byte, sig []byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
return cachingVerifier.VerifyWithOptions(ed25519.PublicKey(pubKey), msg, sig, verifyOptions)
|
||||
return ed25519.Verify(ed25519.PublicKey(pubKey), msg, sig)
|
||||
}
|
||||
|
||||
func (pubKey PubKey) String() string {
|
||||
@@ -189,40 +169,3 @@ func (pubKey PubKey) Equals(other crypto.PubKey) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
// BatchVerifier implements batch verification for ed25519.
|
||||
type BatchVerifier struct {
|
||||
*ed25519.BatchVerifier
|
||||
}
|
||||
|
||||
func NewBatchVerifier() crypto.BatchVerifier {
|
||||
return &BatchVerifier{ed25519.NewBatchVerifier()}
|
||||
}
|
||||
|
||||
func (b *BatchVerifier) Add(key crypto.PubKey, msg, signature []byte) error {
|
||||
pkEd, ok := key.(PubKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("pubkey is not Ed25519")
|
||||
}
|
||||
|
||||
pkBytes := pkEd.Bytes()
|
||||
|
||||
if l := len(pkBytes); l != PubKeySize {
|
||||
return fmt.Errorf("pubkey size is incorrect; expected: %d, got %d", PubKeySize, l)
|
||||
}
|
||||
|
||||
// check that the signature is the correct length
|
||||
if len(signature) != SignatureSize {
|
||||
return errors.New("invalid signature")
|
||||
}
|
||||
|
||||
cachingVerifier.AddWithOptions(b.BatchVerifier, ed25519.PublicKey(pkBytes), msg, signature, verifyOptions)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BatchVerifier) Verify() (bool, []bool) {
|
||||
return b.BatchVerifier.Verify(crypto.CReader())
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestSignAndValidateEd25519(t *testing.T) {
|
||||
|
||||
privKey := ed25519.GenPrivKey()
|
||||
pubKey := privKey.PubKey()
|
||||
|
||||
@@ -27,28 +28,3 @@ func TestSignAndValidateEd25519(t *testing.T) {
|
||||
|
||||
assert.False(t, pubKey.VerifySignature(msg, sig))
|
||||
}
|
||||
|
||||
func TestBatchSafe(t *testing.T) {
|
||||
v := ed25519.NewBatchVerifier()
|
||||
|
||||
for i := 0; i <= 38; i++ {
|
||||
priv := ed25519.GenPrivKey()
|
||||
pub := priv.PubKey()
|
||||
|
||||
var msg []byte
|
||||
if i%2 == 0 {
|
||||
msg = []byte("easter")
|
||||
} else {
|
||||
msg = []byte("egg")
|
||||
}
|
||||
|
||||
sig, err := priv.Sign(msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = v.Add(pub, msg, sig)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
ok, _ := v.Verify()
|
||||
require.True(t, ok)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package merkle
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
)
|
||||
|
||||
@@ -22,27 +20,7 @@ func leafHash(leaf []byte) []byte {
|
||||
return tmhash.Sum(append(leafPrefix, leaf...))
|
||||
}
|
||||
|
||||
// returns tmhash(0x00 || leaf)
|
||||
func leafHashOpt(s hash.Hash, leaf []byte) []byte {
|
||||
s.Reset()
|
||||
s.Write(leafPrefix)
|
||||
s.Write(leaf)
|
||||
return s.Sum(nil)
|
||||
}
|
||||
|
||||
// returns tmhash(0x01 || left || right)
|
||||
func innerHash(left []byte, right []byte) []byte {
|
||||
data := make([]byte, len(innerPrefix)+len(left)+len(right))
|
||||
n := copy(data, innerPrefix)
|
||||
n += copy(data[n:], left)
|
||||
copy(data[n:], right)
|
||||
return tmhash.Sum(data)
|
||||
}
|
||||
|
||||
func innerHashOpt(s hash.Hash, left []byte, right []byte) []byte {
|
||||
s.Reset()
|
||||
s.Write(innerPrefix)
|
||||
s.Write(left)
|
||||
s.Write(right)
|
||||
return s.Sum(nil)
|
||||
return tmhash.Sum(append(innerPrefix, append(left, right...)...))
|
||||
}
|
||||
|
||||
@@ -50,13 +50,13 @@ func ProofsFromByteSlices(items [][]byte) (rootHash []byte, proofs []*Proof) {
|
||||
// Verify that the Proof proves the root hash.
|
||||
// Check sp.Index/sp.Total manually if needed
|
||||
func (sp *Proof) Verify(rootHash []byte, leaf []byte) error {
|
||||
leafHash := leafHash(leaf)
|
||||
if sp.Total < 0 {
|
||||
return errors.New("proof total must be positive")
|
||||
}
|
||||
if sp.Index < 0 {
|
||||
return errors.New("proof index cannot be negative")
|
||||
}
|
||||
leafHash := leafHash(leaf)
|
||||
if !bytes.Equal(sp.LeafHash, leafHash) {
|
||||
return fmt.Errorf("invalid leaf hash: wanted %X got %X", leafHash, sp.LeafHash)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ func TestKeyPath(t *testing.T) {
|
||||
|
||||
res, err := KeyPathToKeys(path.String())
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, len(keys), len(res))
|
||||
|
||||
for i, key := range keys {
|
||||
require.Equal(t, key, res[i])
|
||||
|
||||
@@ -171,12 +171,12 @@ func TestProofValidateBasic(t *testing.T) {
|
||||
}
|
||||
}
|
||||
func TestVoteProtobuf(t *testing.T) {
|
||||
|
||||
_, proofs := ProofsFromByteSlices([][]byte{
|
||||
[]byte("apple"),
|
||||
[]byte("watermelon"),
|
||||
[]byte("kiwi"),
|
||||
})
|
||||
|
||||
testCases := []struct {
|
||||
testName string
|
||||
v1 *Proof
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
package merkle
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"hash"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// HashFromByteSlices computes a Merkle tree where the leaves are the byte slice,
|
||||
// in the provided order. It follows RFC-6962.
|
||||
func HashFromByteSlices(items [][]byte) []byte {
|
||||
return hashFromByteSlices(sha256.New(), items)
|
||||
}
|
||||
|
||||
func hashFromByteSlices(sha hash.Hash, items [][]byte) []byte {
|
||||
switch len(items) {
|
||||
case 0:
|
||||
return emptyHash()
|
||||
case 1:
|
||||
return leafHashOpt(sha, items[0])
|
||||
return leafHash(items[0])
|
||||
default:
|
||||
k := getSplitPoint(int64(len(items)))
|
||||
left := hashFromByteSlices(sha, items[:k])
|
||||
right := hashFromByteSlices(sha, items[k:])
|
||||
return innerHashOpt(sha, left, right)
|
||||
left := HashFromByteSlices(items[:k])
|
||||
right := HashFromByteSlices(items[k:])
|
||||
return innerHash(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +61,7 @@ func hashFromByteSlices(sha hash.Hash, items [][]byte) []byte {
|
||||
// implementation for so little benefit.
|
||||
func HashFromByteSlicesIterative(input [][]byte) []byte {
|
||||
items := make([][]byte, len(input))
|
||||
sha := sha256.New()
|
||||
|
||||
for i, leaf := range input {
|
||||
items[i] = leafHash(leaf)
|
||||
}
|
||||
@@ -84,7 +78,7 @@ func HashFromByteSlicesIterative(input [][]byte) []byte {
|
||||
wp := 0 // write position
|
||||
for rp < size {
|
||||
if rp+1 < size {
|
||||
items[wp] = innerHashOpt(sha, items[rp], items[rp+1])
|
||||
items[wp] = innerHash(items[rp], items[rp+1])
|
||||
rp += 2
|
||||
} else {
|
||||
items[wp] = items[rp]
|
||||
|
||||
@@ -8,8 +8,7 @@ import (
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
secp256k1 "github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||
secp256k1 "github.com/btcsuite/btcd/btcec"
|
||||
"golang.org/x/crypto/ripemd160" //nolint: staticcheck // necessary for Bitcoin address format
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
@@ -43,7 +42,7 @@ func (privKey PrivKey) Bytes() []byte {
|
||||
// PubKey performs the point-scalar multiplication from the privKey on the
|
||||
// generator point to get the pubkey.
|
||||
func (privKey PrivKey) PubKey() crypto.PubKey {
|
||||
_, pubkeyObject := secp256k1.PrivKeyFromBytes(privKey)
|
||||
_, pubkeyObject := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey)
|
||||
|
||||
pk := pubkeyObject.SerializeCompressed()
|
||||
|
||||
@@ -123,18 +122,24 @@ func GenPrivKeySecp256k1(secret []byte) PrivKey {
|
||||
return PrivKey(privKey32)
|
||||
}
|
||||
|
||||
// used to reject malleable signatures
|
||||
// see:
|
||||
// - https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/signature_nocgo.go#L90-L93
|
||||
// - https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/crypto.go#L39
|
||||
var secp256k1halfN = new(big.Int).Rsh(secp256k1.S256().N, 1)
|
||||
|
||||
// Sign creates an ECDSA signature on curve Secp256k1, using SHA256 on the msg.
|
||||
// The returned signature will be of the form R || S (in lower-S form).
|
||||
func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
|
||||
priv, _ := secp256k1.PrivKeyFromBytes(privKey)
|
||||
priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey)
|
||||
|
||||
sig, err := ecdsa.SignCompact(priv, crypto.Sha256(msg), false)
|
||||
sig, err := priv.Sign(crypto.Sha256(msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// remove the first byte which is compactSigRecoveryCode
|
||||
return sig[1:], nil
|
||||
sigBytes := serializeSig(sig)
|
||||
return sigBytes, nil
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
@@ -194,7 +199,7 @@ func (pubKey PubKey) VerifySignature(msg []byte, sigStr []byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
pub, err := secp256k1.ParsePubKey(pubKey)
|
||||
pub, err := secp256k1.ParsePubKey(pubKey, secp256k1.S256())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -203,13 +208,7 @@ func (pubKey PubKey) VerifySignature(msg []byte, sigStr []byte) bool {
|
||||
signature := signatureFromBytes(sigStr)
|
||||
// Reject malleable signatures. libsecp256k1 does this check but btcec doesn't.
|
||||
// see: https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/signature_nocgo.go#L90-L93
|
||||
// Serialize() would negate S value if it is over half order.
|
||||
// Hence, if the signature is different after Serialize() if should be rejected.
|
||||
var modifiedSignature, parseErr = ecdsa.ParseDERSignature(signature.Serialize())
|
||||
if parseErr != nil {
|
||||
return false
|
||||
}
|
||||
if !signature.IsEqual(modifiedSignature) {
|
||||
if signature.S.Cmp(secp256k1halfN) > 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -218,10 +217,21 @@ func (pubKey PubKey) VerifySignature(msg []byte, sigStr []byte) bool {
|
||||
|
||||
// Read Signature struct from R || S. Caller needs to ensure
|
||||
// that len(sigStr) == 64.
|
||||
func signatureFromBytes(sigStr []byte) *ecdsa.Signature {
|
||||
var r secp256k1.ModNScalar
|
||||
r.SetByteSlice(sigStr[:32])
|
||||
var s secp256k1.ModNScalar
|
||||
s.SetByteSlice(sigStr[32:64])
|
||||
return ecdsa.NewSignature(&r, &s)
|
||||
func signatureFromBytes(sigStr []byte) *secp256k1.Signature {
|
||||
return &secp256k1.Signature{
|
||||
R: new(big.Int).SetBytes(sigStr[:32]),
|
||||
S: new(big.Int).SetBytes(sigStr[32:64]),
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize signature to R || S.
|
||||
// R, S are padded to 32 bytes respectively.
|
||||
func serializeSig(sig *secp256k1.Signature) []byte {
|
||||
rBytes := sig.R.Bytes()
|
||||
sBytes := sig.S.Bytes()
|
||||
sigBytes := make([]byte, 64)
|
||||
// 0 pad the byte arrays from the left if they aren't big enough.
|
||||
copy(sigBytes[32-len(rBytes):32], rBytes)
|
||||
copy(sigBytes[64-len(sBytes):64], sBytes)
|
||||
return sigBytes
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
secp256k1 "github.com/btcsuite/btcd/btcec/v2"
|
||||
secp256k1 "github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
func Test_genPrivKey(t *testing.T) {
|
||||
@@ -54,30 +54,20 @@ func TestSignatureVerificationAndRejectUpperS(t *testing.T) {
|
||||
priv := GenPrivKey()
|
||||
sigStr, err := priv.Sign(msg)
|
||||
require.NoError(t, err)
|
||||
var r secp256k1.ModNScalar
|
||||
r.SetByteSlice(sigStr[:32])
|
||||
var s secp256k1.ModNScalar
|
||||
s.SetByteSlice(sigStr[32:64])
|
||||
require.False(t, s.IsOverHalfOrder())
|
||||
sig := signatureFromBytes(sigStr)
|
||||
require.False(t, sig.S.Cmp(secp256k1halfN) > 0)
|
||||
|
||||
pub := priv.PubKey()
|
||||
require.True(t, pub.VerifySignature(msg, sigStr))
|
||||
|
||||
// malleate:
|
||||
var S256 secp256k1.ModNScalar
|
||||
S256.SetByteSlice(secp256k1.S256().N.Bytes())
|
||||
s.Negate().Add(&S256)
|
||||
require.True(t, s.IsOverHalfOrder())
|
||||
|
||||
rBytes := r.Bytes()
|
||||
sBytes := s.Bytes()
|
||||
malSigStr := make([]byte, 64)
|
||||
copy(malSigStr[32-len(rBytes):32], rBytes[:])
|
||||
copy(malSigStr[64-len(sBytes):64], sBytes[:])
|
||||
sig.S.Sub(secp256k1.S256().CurveParams.N, sig.S)
|
||||
require.True(t, sig.S.Cmp(secp256k1halfN) > 0)
|
||||
malSigStr := serializeSig(sig)
|
||||
|
||||
require.False(t, pub.VerifySignature(msg, malSigStr),
|
||||
"VerifyBytes incorrect with malleated & invalid S. sig=%v, key=%v",
|
||||
malSigStr,
|
||||
sig,
|
||||
priv,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil/base58"
|
||||
"github.com/btcsuite/btcutil/base58"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
|
||||
underlyingSecp256k1 "github.com/btcsuite/btcd/btcec/v2"
|
||||
underlyingSecp256k1 "github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
type keyData struct {
|
||||
@@ -75,7 +75,7 @@ func TestSecp256k1LoadPrivkeyAndSerializeIsIdentity(t *testing.T) {
|
||||
|
||||
// This function creates a private and public key in the underlying libraries format.
|
||||
// The private key is basically calling new(big.Int).SetBytes(pk), which removes leading zero bytes
|
||||
priv, _ := underlyingSecp256k1.PrivKeyFromBytes(privKeyBytes[:])
|
||||
priv, _ := underlyingSecp256k1.PrivKeyFromBytes(underlyingSecp256k1.S256(), privKeyBytes[:])
|
||||
// this takes the bytes returned by `(big int).Bytes()`, and if the length is less than 32 bytes,
|
||||
// pads the bytes from the left with zero bytes. Therefore these two functions composed
|
||||
// result in the identity function on privKeyBytes, hence the following equality check
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package sr25519
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/oasisprotocol/curve25519-voi/primitives/sr25519"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
)
|
||||
|
||||
var _ crypto.BatchVerifier = &BatchVerifier{}
|
||||
|
||||
// BatchVerifier implements batch verification for sr25519.
|
||||
type BatchVerifier struct {
|
||||
*sr25519.BatchVerifier
|
||||
}
|
||||
|
||||
func NewBatchVerifier() crypto.BatchVerifier {
|
||||
return &BatchVerifier{sr25519.NewBatchVerifier()}
|
||||
}
|
||||
|
||||
func (b *BatchVerifier) Add(key crypto.PubKey, msg, signature []byte) error {
|
||||
pk, ok := key.(PubKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("sr25519: pubkey is not sr25519")
|
||||
}
|
||||
|
||||
var srpk sr25519.PublicKey
|
||||
if err := srpk.UnmarshalBinary(pk); err != nil {
|
||||
return fmt.Errorf("sr25519: invalid public key: %w", err)
|
||||
}
|
||||
|
||||
var sig sr25519.Signature
|
||||
if err := sig.UnmarshalBinary(signature); err != nil {
|
||||
return fmt.Errorf("sr25519: unable to decode signature: %w", err)
|
||||
}
|
||||
|
||||
st := signingCtx.NewTranscriptBytes(msg)
|
||||
b.BatchVerifier.Add(&srpk, st, &sig)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BatchVerifier) Verify() (bool, []bool) {
|
||||
return b.BatchVerifier.Verify(crypto.CReader())
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
package sr25519
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/internal/benchmarking"
|
||||
)
|
||||
@@ -27,42 +24,3 @@ func BenchmarkVerification(b *testing.B) {
|
||||
priv := GenPrivKey()
|
||||
benchmarking.BenchmarkVerification(b, priv)
|
||||
}
|
||||
|
||||
func BenchmarkVerifyBatch(b *testing.B) {
|
||||
msg := []byte("BatchVerifyTest")
|
||||
|
||||
for _, sigsCount := range []int{1, 8, 64, 1024} {
|
||||
sigsCount := sigsCount
|
||||
b.Run(fmt.Sprintf("sig-count-%d", sigsCount), func(b *testing.B) {
|
||||
// Pre-generate all of the keys, and signatures, but do not
|
||||
// benchmark key-generation and signing.
|
||||
pubs := make([]crypto.PubKey, 0, sigsCount)
|
||||
sigs := make([][]byte, 0, sigsCount)
|
||||
for i := 0; i < sigsCount; i++ {
|
||||
priv := GenPrivKey()
|
||||
sig, _ := priv.Sign(msg)
|
||||
pubs = append(pubs, priv.PubKey().(PubKey))
|
||||
sigs = append(sigs, sig)
|
||||
}
|
||||
b.ResetTimer()
|
||||
|
||||
b.ReportAllocs()
|
||||
// NOTE: dividing by n so that metrics are per-signature
|
||||
for i := 0; i < b.N/sigsCount; i++ {
|
||||
// The benchmark could just benchmark the Verify()
|
||||
// routine, but there is non-trivial overhead associated
|
||||
// with BatchVerifier.Add(), which should be included
|
||||
// in the benchmark.
|
||||
v := NewBatchVerifier()
|
||||
for i := 0; i < sigsCount; i++ {
|
||||
err := v.Add(pubs[i], msg, sigs[i])
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
if ok, _ := v.Verify(); !ok {
|
||||
b.Fatal("signature set failed batch verification")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
package sr25519
|
||||
|
||||
import tmjson "github.com/tendermint/tendermint/libs/json"
|
||||
import (
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
tmjson "github.com/tendermint/tendermint/libs/json"
|
||||
)
|
||||
|
||||
var _ crypto.PrivKey = PrivKey{}
|
||||
|
||||
const (
|
||||
PrivKeyName = "tendermint/PrivKeySr25519"
|
||||
PubKeyName = "tendermint/PubKeySr25519"
|
||||
|
||||
// SignatureSize is the size of an Edwards25519 signature. Namely the size of a compressed
|
||||
// Sr25519 point, and a field element. Both of which are 32 bytes.
|
||||
SignatureSize = 64
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
tmjson.RegisterType(PubKey{}, PubKeyName)
|
||||
tmjson.RegisterType(PrivKey{}, PrivKeyName)
|
||||
}
|
||||
|
||||
@@ -1,126 +1,76 @@
|
||||
package sr25519
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/oasisprotocol/curve25519-voi/primitives/sr25519"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
schnorrkel "github.com/ChainSafe/go-schnorrkel"
|
||||
)
|
||||
|
||||
var (
|
||||
_ crypto.PrivKey = PrivKey{}
|
||||
// PrivKeySize is the number of bytes in an Sr25519 private key.
|
||||
const PrivKeySize = 32
|
||||
|
||||
signingCtx = sr25519.NewSigningContext([]byte{})
|
||||
)
|
||||
|
||||
const (
|
||||
// PrivKeySize is the number of bytes in an Sr25519 private key.
|
||||
PrivKeySize = 32
|
||||
|
||||
KeyType = "sr25519"
|
||||
)
|
||||
|
||||
// PrivKey implements crypto.PrivKey.
|
||||
type PrivKey struct {
|
||||
msk sr25519.MiniSecretKey
|
||||
kp *sr25519.KeyPair
|
||||
}
|
||||
// PrivKeySr25519 implements crypto.PrivKey.
|
||||
type PrivKey []byte
|
||||
|
||||
// Bytes returns the byte representation of the PrivKey.
|
||||
func (privKey PrivKey) Bytes() []byte {
|
||||
if privKey.kp == nil {
|
||||
return nil
|
||||
}
|
||||
return privKey.msk[:]
|
||||
return []byte(privKey)
|
||||
}
|
||||
|
||||
// Sign produces a signature on the provided message.
|
||||
func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
|
||||
if privKey.kp == nil {
|
||||
return nil, fmt.Errorf("sr25519: uninitialized private key")
|
||||
}
|
||||
|
||||
st := signingCtx.NewTranscriptBytes(msg)
|
||||
|
||||
sig, err := privKey.kp.Sign(crypto.CReader(), st)
|
||||
var p [PrivKeySize]byte
|
||||
copy(p[:], privKey)
|
||||
miniSecretKey, err := schnorrkel.NewMiniSecretKeyFromRaw(p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sr25519: failed to sign message: %w", err)
|
||||
return []byte{}, err
|
||||
}
|
||||
secretKey := miniSecretKey.ExpandEd25519()
|
||||
|
||||
sigBytes, err := sig.MarshalBinary()
|
||||
signingContext := schnorrkel.NewSigningContext([]byte{}, msg)
|
||||
|
||||
sig, err := secretKey.Sign(signingContext)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sr25519: failed to serialize signature: %w", err)
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
return sigBytes, nil
|
||||
sigBytes := sig.Encode()
|
||||
return sigBytes[:], nil
|
||||
}
|
||||
|
||||
// PubKey gets the corresponding public key from the private key.
|
||||
func (privKey PrivKey) PubKey() crypto.PubKey {
|
||||
if privKey.kp == nil {
|
||||
panic("sr25519: uninitialized private key")
|
||||
}
|
||||
|
||||
b, err := privKey.kp.PublicKey().MarshalBinary()
|
||||
var p [PrivKeySize]byte
|
||||
copy(p[:], privKey)
|
||||
miniSecretKey, err := schnorrkel.NewMiniSecretKeyFromRaw(p)
|
||||
if err != nil {
|
||||
panic("sr25519: failed to serialize public key: " + err.Error())
|
||||
panic(fmt.Sprintf("Invalid private key: %v", err))
|
||||
}
|
||||
secretKey := miniSecretKey.ExpandEd25519()
|
||||
|
||||
return PubKey(b)
|
||||
pubkey, err := secretKey.Public()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Could not generate public key: %v", err))
|
||||
}
|
||||
key := pubkey.Encode()
|
||||
return PubKey(key[:])
|
||||
}
|
||||
|
||||
// Equals - you probably don't need to use this.
|
||||
// Runs in constant time based on length of the keys.
|
||||
func (privKey PrivKey) Equals(other crypto.PrivKey) bool {
|
||||
if otherSr, ok := other.(PrivKey); ok {
|
||||
return privKey.msk.Equal(&otherSr.msk)
|
||||
if otherEd, ok := other.(PrivKey); ok {
|
||||
return subtle.ConstantTimeCompare(privKey[:], otherEd[:]) == 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (privKey PrivKey) Type() string {
|
||||
return KeyType
|
||||
}
|
||||
|
||||
func (privKey PrivKey) MarshalJSON() ([]byte, error) {
|
||||
var b []byte
|
||||
|
||||
// Handle uninitialized private keys gracefully.
|
||||
if privKey.kp != nil {
|
||||
b = privKey.Bytes()
|
||||
}
|
||||
|
||||
return json.Marshal(b)
|
||||
}
|
||||
|
||||
func (privKey *PrivKey) UnmarshalJSON(data []byte) error {
|
||||
for i := range privKey.msk {
|
||||
privKey.msk[i] = 0
|
||||
}
|
||||
privKey.kp = nil
|
||||
|
||||
var b []byte
|
||||
if err := json.Unmarshal(data, &b); err != nil {
|
||||
return fmt.Errorf("sr25519: failed to deserialize JSON: %w", err)
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
msk, err := sr25519.NewMiniSecretKeyFromBytes(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sk := msk.ExpandEd25519()
|
||||
|
||||
privKey.msk = *msk
|
||||
privKey.kp = sk.KeyPair()
|
||||
|
||||
return nil
|
||||
return keyType
|
||||
}
|
||||
|
||||
// GenPrivKey generates a new sr25519 private key.
|
||||
@@ -131,18 +81,19 @@ func GenPrivKey() PrivKey {
|
||||
}
|
||||
|
||||
// genPrivKey generates a new sr25519 private key using the provided reader.
|
||||
func genPrivKey(rng io.Reader) PrivKey {
|
||||
msk, err := sr25519.GenerateMiniSecretKey(rng)
|
||||
func genPrivKey(rand io.Reader) PrivKey {
|
||||
var seed [64]byte
|
||||
|
||||
out := make([]byte, 64)
|
||||
_, err := io.ReadFull(rand, out)
|
||||
if err != nil {
|
||||
panic("sr25519: failed to generate MiniSecretKey: " + err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sk := msk.ExpandEd25519()
|
||||
copy(seed[:], out)
|
||||
|
||||
return PrivKey{
|
||||
msk: *msk,
|
||||
kp: sk.KeyPair(),
|
||||
}
|
||||
key := schnorrkel.NewMiniSecretKey(seed).ExpandEd25519().Encode()
|
||||
return key[:]
|
||||
}
|
||||
|
||||
// GenPrivKeyFromSecret hashes the secret with SHA2, and uses
|
||||
@@ -151,14 +102,9 @@ func genPrivKey(rng io.Reader) PrivKey {
|
||||
// if it's derived from user input.
|
||||
func GenPrivKeyFromSecret(secret []byte) PrivKey {
|
||||
seed := crypto.Sha256(secret) // Not Ripemd160 because we want 32 bytes.
|
||||
|
||||
var privKey PrivKey
|
||||
if err := privKey.msk.UnmarshalBinary(seed); err != nil {
|
||||
panic("sr25519: failed to deserialize MiniSecretKey: " + err.Error())
|
||||
}
|
||||
|
||||
sk := privKey.msk.ExpandEd25519()
|
||||
privKey.kp = sk.KeyPair()
|
||||
|
||||
return privKey
|
||||
var bz [PrivKeySize]byte
|
||||
copy(bz[:], seed)
|
||||
privKey, _ := schnorrkel.NewMiniSecretKeyFromRaw(bz)
|
||||
key := privKey.ExpandEd25519().Encode()
|
||||
return key[:]
|
||||
}
|
||||
|
||||
@@ -4,30 +4,25 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/oasisprotocol/curve25519-voi/primitives/sr25519"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
|
||||
schnorrkel "github.com/ChainSafe/go-schnorrkel"
|
||||
)
|
||||
|
||||
var _ crypto.PubKey = PubKey{}
|
||||
|
||||
// PubKeySize is the number of bytes in an Sr25519 public key.
|
||||
const (
|
||||
// PubKeySize is the number of bytes in an Sr25519 public key.
|
||||
PubKeySize = 32
|
||||
|
||||
// SignatureSize is the size of a Sr25519 signature in bytes.
|
||||
SignatureSize = 64
|
||||
keyType = "sr25519"
|
||||
)
|
||||
|
||||
// PubKey implements crypto.PubKey for the Sr25519 signature scheme.
|
||||
// PubKeySr25519 implements crypto.PubKey for the Sr25519 signature scheme.
|
||||
type PubKey []byte
|
||||
|
||||
// Address is the SHA256-20 of the raw pubkey bytes.
|
||||
func (pubKey PubKey) Address() crypto.Address {
|
||||
if len(pubKey) != PubKeySize {
|
||||
panic("pubkey is incorrect size")
|
||||
}
|
||||
return crypto.Address(tmhash.SumTruncated(pubKey[:]))
|
||||
}
|
||||
|
||||
@@ -36,35 +31,47 @@ func (pubKey PubKey) Bytes() []byte {
|
||||
return []byte(pubKey)
|
||||
}
|
||||
|
||||
// Equals - checks that two public keys are the same time
|
||||
// Runs in constant time based on length of the keys.
|
||||
func (pubKey PubKey) Equals(other crypto.PubKey) bool {
|
||||
if otherSr, ok := other.(PubKey); ok {
|
||||
return bytes.Equal(pubKey[:], otherSr[:])
|
||||
func (pubKey PubKey) VerifySignature(msg []byte, sig []byte) bool {
|
||||
// make sure we use the same algorithm to sign
|
||||
if len(sig) != SignatureSize {
|
||||
return false
|
||||
}
|
||||
var sig64 [SignatureSize]byte
|
||||
copy(sig64[:], sig)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (pubKey PubKey) VerifySignature(msg []byte, sigBytes []byte) bool {
|
||||
var srpk sr25519.PublicKey
|
||||
if err := srpk.UnmarshalBinary(pubKey); err != nil {
|
||||
publicKey := &(schnorrkel.PublicKey{})
|
||||
var p [PubKeySize]byte
|
||||
copy(p[:], pubKey)
|
||||
err := publicKey.Decode(p)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var sig sr25519.Signature
|
||||
if err := sig.UnmarshalBinary(sigBytes); err != nil {
|
||||
signingContext := schnorrkel.NewSigningContext([]byte{}, msg)
|
||||
|
||||
signature := &(schnorrkel.Signature{})
|
||||
err = signature.Decode(sig64)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
st := signingCtx.NewTranscriptBytes(msg)
|
||||
return srpk.Verify(st, &sig)
|
||||
return publicKey.Verify(signature, signingContext)
|
||||
}
|
||||
|
||||
func (pubKey PubKey) String() string {
|
||||
return fmt.Sprintf("PubKeySr25519{%X}", []byte(pubKey))
|
||||
}
|
||||
|
||||
func (pubKey PubKey) Type() string {
|
||||
return KeyType
|
||||
// Equals - checks that two public keys are the same time
|
||||
// Runs in constant time based on length of the keys.
|
||||
func (pubKey PubKey) Equals(other crypto.PubKey) bool {
|
||||
if otherEd, ok := other.(PubKey); ok {
|
||||
return bytes.Equal(pubKey[:], otherEd[:])
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (pubKey PubKey) Type() string {
|
||||
return keyType
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package sr25519_test
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -13,6 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestSignAndValidateSr25519(t *testing.T) {
|
||||
|
||||
privKey := sr25519.GenPrivKey()
|
||||
pubKey := privKey.PubKey()
|
||||
|
||||
@@ -30,69 +29,3 @@ func TestSignAndValidateSr25519(t *testing.T) {
|
||||
|
||||
assert.False(t, pubKey.VerifySignature(msg, sig))
|
||||
}
|
||||
|
||||
func TestBatchSafe(t *testing.T) {
|
||||
v := sr25519.NewBatchVerifier()
|
||||
vFail := sr25519.NewBatchVerifier()
|
||||
for i := 0; i <= 38; i++ {
|
||||
priv := sr25519.GenPrivKey()
|
||||
pub := priv.PubKey()
|
||||
|
||||
var msg []byte
|
||||
if i%2 == 0 {
|
||||
msg = []byte("easter")
|
||||
} else {
|
||||
msg = []byte("egg")
|
||||
}
|
||||
|
||||
sig, err := priv.Sign(msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = v.Add(pub, msg, sig)
|
||||
require.NoError(t, err)
|
||||
|
||||
switch i % 2 {
|
||||
case 0:
|
||||
err = vFail.Add(pub, msg, sig)
|
||||
case 1:
|
||||
msg[2] ^= byte(0x01)
|
||||
err = vFail.Add(pub, msg, sig)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
ok, valid := v.Verify()
|
||||
require.True(t, ok, "failed batch verification")
|
||||
for i, ok := range valid {
|
||||
require.Truef(t, ok, "sig[%d] should be marked valid", i)
|
||||
}
|
||||
|
||||
ok, valid = vFail.Verify()
|
||||
require.False(t, ok, "succeeded batch verification (invalid batch)")
|
||||
for i, ok := range valid {
|
||||
expected := (i % 2) == 0
|
||||
require.Equalf(t, expected, ok, "sig[%d] should be %v", i, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSON(t *testing.T) {
|
||||
privKey := sr25519.GenPrivKey()
|
||||
|
||||
t.Run("PrivKey", func(t *testing.T) {
|
||||
b, err := json.Marshal(privKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
// b should be the base64 encoded MiniSecretKey, enclosed by doublequotes.
|
||||
b64 := base64.StdEncoding.EncodeToString(privKey.Bytes())
|
||||
b64 = "\"" + b64 + "\""
|
||||
require.Equal(t, []byte(b64), b)
|
||||
|
||||
var privKey2 sr25519.PrivKey
|
||||
err = json.Unmarshal(b, &privKey2)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, privKey2.Bytes(), sr25519.PrivKeySize)
|
||||
require.EqualValues(t, privKey.Bytes(), privKey2.Bytes())
|
||||
})
|
||||
|
||||
// PubKeys are just []byte, so there is no special handling.
|
||||
}
|
||||
|
||||
@@ -63,4 +63,3 @@
|
||||
/redirects/master/spec/blockchain/encoding.html https://github.com/tendermint/tendermint/blob/v0.34.x/spec/blockchain/encoding.md
|
||||
/redirects/master/spec/blockchain/blockchain.html https://github.com/tendermint/tendermint/blob/v0.34.x/spec/blockchain/blockchain.md
|
||||
/redirects/master/spec/blockchain/index.html https://github.com/tendermint/tendermint/blob/v0.34.x/spec/blockchain/readme.md
|
||||
/redirects/master/tutorials/go.html /v0.34/tutorials/go.html
|
||||
@@ -21,7 +21,7 @@ Tendermint?](introduction/what-is-tendermint.md).
|
||||
|
||||
To get started quickly with an example application, see the [quick start guide](introduction/quick-start.md).
|
||||
|
||||
To learn about application development on Tendermint, see the [Application Blockchain Interface](https://github.com/tendermint/tendermint/tree/main/spec/abci).
|
||||
To learn about application development on Tendermint, see the [Application Blockchain Interface](https://github.com/tendermint/tendermint/tree/v0.37.x/spec/abci).
|
||||
|
||||
For more details on using Tendermint, see the respective documentation for
|
||||
[Tendermint Core](tendermint-core/), [benchmarking and monitoring](tools/), and [network deployments](networks/).
|
||||
@@ -30,4 +30,4 @@ To find out about the Tendermint ecosystem you can go [here](https://github.com/
|
||||
|
||||
## Contribute
|
||||
|
||||
To contribute to the documentation, see [this file](https://github.com/tendermint/tendermint/blob/main/docs/DOCS_README.md) for details of the build process and considerations when making changes.
|
||||
To contribute to the documentation, see [this file](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/DOCS_README.md) for details of the build process and considerations when making changes.
|
||||
|
||||
@@ -136,7 +136,7 @@ response.
|
||||
|
||||
The server may be generic for a particular language, and we provide a
|
||||
[reference implementation in
|
||||
Golang](https://github.com/tendermint/tendermint/tree/main/abci/server). See the
|
||||
Golang](https://github.com/tendermint/tendermint/tree/v0.37.x/abci/server). See the
|
||||
[list of other ABCI implementations](https://github.com/tendermint/awesome#ecosystem) for servers in
|
||||
other languages.
|
||||
|
||||
@@ -253,13 +253,14 @@ Similarly, you could put the commands in a file and run
|
||||
Want to write an app in your favorite language?! We'd be happy
|
||||
to add you to our [ecosystem](https://github.com/tendermint/awesome#ecosystem)!
|
||||
See [funding](https://github.com/interchainio/funding) opportunities from the
|
||||
[Interchain Foundation](https://interchain.io) for implementations in new languages and more.
|
||||
[Interchain Foundation](https://interchain.io/) for implementations in new languages and more.
|
||||
|
||||
The `abci-cli` is designed strictly for testing and debugging. In a real
|
||||
deployment, the role of sending messages is taken by Tendermint, which
|
||||
connects to the app using three separate connections, each with its own
|
||||
pattern of messages.
|
||||
|
||||
For examples of running an ABCI app with
|
||||
For more information, see the [application developers
|
||||
guide](./app-development.md). For examples of running an ABCI app with
|
||||
Tendermint, see the [getting started guide](./getting-started.md).
|
||||
Next is the ABCI specification.
|
||||
|
||||
@@ -55,6 +55,6 @@ Tendermint.
|
||||
See the following for more extensive documentation:
|
||||
|
||||
- [Interchain Standard for the Light-Client REST API](https://github.com/cosmos/cosmos-sdk/pull/1028)
|
||||
- [Tendermint RPC Docs](https://docs.tendermint.com/main/rpc/)
|
||||
- [Tendermint RPC Docs](https://docs.tendermint.com/v0.37/rpc/)
|
||||
- [Tendermint in Production](../tendermint-core/running-in-production.md)
|
||||
- [ABCI spec](https://github.com/tendermint/spec/tree/95cf253b6df623066ff7cd4074a94e7a3f147c7a/spec/abci)
|
||||
|
||||
@@ -15,7 +15,7 @@ the block itself is never stored.
|
||||
Each event contains a type and a list of attributes, which are key-value pairs
|
||||
denoting something about what happened during the method's execution. For more
|
||||
details on `Events`, see the
|
||||
[ABCI](https://github.com/tendermint/tendermint/blob/main/spec/abci/abci++_basic_concepts.md#events)
|
||||
[ABCI](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/abci/abci.md#events)
|
||||
documentation.
|
||||
|
||||
An `Event` has a composite key associated with it. A `compositeKey` is
|
||||
@@ -146,7 +146,7 @@ You can query for a paginated set of transaction by their events by calling the
|
||||
curl "localhost:26657/tx_search?query=\"message.sender='cosmos1...'\"&prove=true"
|
||||
```
|
||||
|
||||
Check out [API docs](https://docs.tendermint.com/main/rpc/#/Info/tx_search)
|
||||
Check out [API docs](https://docs.tendermint.com/v0.37/rpc/#/Info/tx_search)
|
||||
for more information on query syntax and other options.
|
||||
|
||||
## Subscribing to Transactions
|
||||
@@ -165,7 +165,7 @@ a query to `/subscribe` RPC endpoint.
|
||||
}
|
||||
```
|
||||
|
||||
Check out [API docs](https://docs.tendermint.com/main/rpc/#subscribe) for more information
|
||||
Check out [API docs](https://docs.tendermint.com/v0.37/rpc/#subscribe) for more information
|
||||
on query syntax and other options.
|
||||
|
||||
## Querying Blocks Events
|
||||
@@ -177,5 +177,5 @@ You can query for a paginated set of blocks by their events by calling the
|
||||
curl "localhost:26657/block_search?query=\"block.height > 10 AND val_set.num_changed > 0\""
|
||||
```
|
||||
|
||||
Check out [API docs](https://docs.tendermint.com/main/rpc/#/Info/block_search)
|
||||
Check out [API docs](https://docs.tendermint.com/v0.37/rpc/#/Info/block_search)
|
||||
for more information on query syntax and other options.
|
||||
|
||||
@@ -63,12 +63,14 @@ Note the context/background should be written in the present tense.
|
||||
- [ADR-055: Protobuf-Design](./adr-055-protobuf-design.md)
|
||||
- [ADR-056: Light-Client-Amnesia-Attacks](./adr-056-light-client-amnesia-attacks.md)
|
||||
- [ADR-059: Evidence-Composition-and-Lifecycle](./adr-059-evidence-composition-and-lifecycle.md)
|
||||
- [ADR-065: Custom Event Indexing](./adr-065-custom-event-indexing.md)
|
||||
- [ADR-062: P2P-Architecture](./adr-062-p2p-architecture.md)
|
||||
- [ADR-063: Privval-gRPC](./adr-063-privval-grpc.md)
|
||||
- [ADR-066: E2E-Testing](./adr-066-e2e-testing.md)
|
||||
- [ADR-072: Restore Requests for Comments](./adr-072-request-for-comments.md)
|
||||
- [ADR-076: Combine Spec and Tendermint Repositories](./adr-076-combine-spec-repo.md)
|
||||
- [ADR-077: Configurable Block Retention](./adr-077-block-retention.md)
|
||||
- [ADR-077: Block Retention](./adr-077-block-retention.md)
|
||||
- [ADR-078: Non-zero Genesis](./adr-078-nonzero-genesis.md)
|
||||
- [ADR-079: ED25519 Verification](./adr-079-ed25519-verification.md)
|
||||
- [ADR-080: Reverse Sync](./adr-080-reverse-sync.md)
|
||||
|
||||
### Accepted
|
||||
|
||||
@@ -76,10 +78,13 @@ Note the context/background should be written in the present tense.
|
||||
- [ADR-024: Sign-Bytes](./adr-024-sign-bytes.md)
|
||||
- [ADR-035: Documentation](./adr-035-documentation.md)
|
||||
- [ADR-039: Peer-Behaviour](./adr-039-peer-behaviour.md)
|
||||
- [ADR-063: Privval-gRPC](./adr-063-privval-grpc.md)
|
||||
- [ADR-060: Go-API-Stability](./adr-060-go-api-stability.md)
|
||||
- [ADR-061: P2P-Refactor-Scope](./adr-061-p2p-refactor-scope.md)
|
||||
- [ADR-065: Custom Event Indexing](./adr-065-custom-event-indexing.md)
|
||||
- [ADR-068: Reverse-Sync](./adr-068-reverse-sync.md)
|
||||
- [ADR-067: Mempool Refactor](./adr-067-mempool-refactor.md)
|
||||
- [ADR-075: RPC Event Subscription Interface](./adr-075-rpc-subscription.md)
|
||||
- [ADR-079: Ed25519 Verification](./adr-079-ed25519-verification.md)
|
||||
- [ADR-076: Combine Spec and Tendermint Repositories](./adr-076-combine-spec-repo.md)
|
||||
- [ADR-081: Protocol Buffers Management](./adr-081-protobuf-mgmt.md)
|
||||
|
||||
### Deprecated
|
||||
@@ -108,13 +113,8 @@ None
|
||||
- [ADR-045: ABCI-Evidence](./adr-045-abci-evidence.md)
|
||||
- [ADR-050: Improved Trusted Peering](./adr-050-improved-trusted-peering.md)
|
||||
- [ADR-057: RPC](./adr-057-RPC.md)
|
||||
- [ADR-060: Go-API-Stability](./adr-060-go-api-stability.md)
|
||||
- [ADR-061: P2P-Refactor-Scope](./adr-061-p2p-refactor-scope.md)
|
||||
- [ADR-062: P2P-Architecture](./adr-062-p2p-architecture.md)
|
||||
- [ADR-064: Batch Verification](./adr-064-batch-verification.md)
|
||||
- [ADR-068: Reverse-Sync](./adr-068-reverse-sync.md)
|
||||
- [ADR-069: Node Initialization](./adr-069-flexible-node-initialization.md)
|
||||
- [ADR-071: Proposer-Based Timestamps](./adr-071-proposer-based-timestamps.md)
|
||||
- [ADR-073: Adopt LibP2P](./adr-073-libp2p.md)
|
||||
- [ADR-074: Migrate Timeout Parameters to Consensus Parameters](./adr-074-timeout-params.md)
|
||||
- [ADR-080: Reverse Sync](./adr-080-reverse-sync.md)
|
||||
|
||||
@@ -33,7 +33,7 @@ See the [references](#references) for more.
|
||||
|
||||
The native proto library in Go generates inflexible and verbose code.
|
||||
Many in the Go community have adopted a fork called
|
||||
[gogoproto](https://github.com/cosmos/gogoproto) that provides a
|
||||
[gogoproto](https://github.com/gogo/protobuf) that provides a
|
||||
variety of features aimed to improve the developer experience.
|
||||
While `gogoproto` is nice, it creates an additional dependency, and compiling
|
||||
the protobuf types for other languages has been reported to fail when `gogoproto` is used.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
## Context
|
||||
|
||||
ABCI tags were first described in [ADR 002](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-002-event-subscription.md).
|
||||
ABCI tags were first described in [ADR 002](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-002-event-subscription.md).
|
||||
They are key-value pairs that can be used to index transactions.
|
||||
|
||||
Currently, ABCI messages return a list of tags to describe an
|
||||
|
||||
@@ -16,7 +16,7 @@ The messages exchanged between tendermint and a remote signer currently live in
|
||||
|
||||
[privval/socket.go]: https://github.com/tendermint/tendermint/blob/d419fffe18531317c28c29a292ad7d253f6cafdf/privval/socket.go#L496-L502
|
||||
[issue#1622]: https://github.com/tendermint/tendermint/issues/1622
|
||||
[types]: https://github.com/tendermint/tendermint/tree/main/types
|
||||
[types]: https://github.com/tendermint/tendermint/tree/v0.37.x/types
|
||||
|
||||
|
||||
## Decision
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## Context
|
||||
|
||||
The blockchain reactor is responsible for two high level processes:sending/receiving blocks from peers and FastSync-ing blocks to catch upnode who is far behind. The goal of [ADR-40](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-040-blockchain-reactor-refactor.md) was to refactor these two processes by separating business logic currently wrapped up in go-channels into pure `handle*` functions. While the ADR specified what the final form of the reactor might look like it lacked guidance on intermediary steps to get there.
|
||||
The blockchain reactor is responsible for two high level processes:sending/receiving blocks from peers and FastSync-ing blocks to catch upnode who is far behind. The goal of [ADR-40](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-040-blockchain-reactor-refactor.md) was to refactor these two processes by separating business logic currently wrapped up in go-channels into pure `handle*` functions. While the ADR specified what the final form of the reactor might look like it lacked guidance on intermediary steps to get there.
|
||||
The following diagram illustrates the state of the [blockchain-reorg](https://github.com/tendermint/tendermint/pull/3561) reactor which will be referred to as `v1`.
|
||||
|
||||
.
|
||||
This ADR is meant to specify the missing components and control necessary to achieve [ADR-40](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-040-blockchain-reactor-refactor.md).
|
||||
|
||||
## Decision
|
||||
|
||||
@@ -41,7 +41,7 @@ Diagram](https://github.com/tendermint/tendermint/blob/5cf570690f989646fb3b615b7
|
||||
|
||||
### Reactor changes in detail
|
||||
|
||||
The reactor will include a demultiplexing routine which will send each message to each sub routine for independent processing. Each sub routine will then select the messages it's interested in and call the handle specific function specified in [ADR-40](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-040-blockchain-reactor-refactor.md). The demuxRoutine acts as "pacemaker" setting the time in which events are expected to be handled.
|
||||
The reactor will include a demultiplexing routine which will send each message to each sub routine for independent processing. Each sub routine will then select the messages it's interested in and call the handle specific function specified in [ADR-40](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-040-blockchain-reactor-refactor.md). The demuxRoutine acts as "pacemaker" setting the time in which events are expected to be handled.
|
||||
|
||||
```go
|
||||
func demuxRoutine(msgs, scheduleMsgs, processorMsgs, ioMsgs) {
|
||||
@@ -400,5 +400,5 @@ Implemented
|
||||
|
||||
## References
|
||||
|
||||
- [ADR-40](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-040-blockchain-reactor-refactor.md): The original blockchain reactor re-org proposal
|
||||
- [ADR-40](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-040-blockchain-reactor-refactor.md): The original blockchain reactor re-org proposal
|
||||
- [Blockchain re-org](https://github.com/tendermint/tendermint/pull/3561): The current blockchain reactor re-org implementation (v1)
|
||||
|
||||
@@ -32,7 +32,7 @@ fork the network at some point in its prior history. See Vitalik’s post at
|
||||
Subjectivity](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/).
|
||||
|
||||
Currently, Tendermint provides a lite client implementation in the
|
||||
[light](https://github.com/tendermint/tendermint/tree/main/light) package. This
|
||||
[light](https://github.com/tendermint/tendermint/tree/v0.37.x/light) package. This
|
||||
lite client implements a bisection algorithm that tries to use a binary search
|
||||
to find the minimum number of block headers where the validator set voting
|
||||
power changes are less than < 1/3rd. This interface does not support weak
|
||||
@@ -84,7 +84,7 @@ The linear verification algorithm requires downloading all headers
|
||||
between the `TrustHeight` and the `LatestHeight`. The lite client downloads the
|
||||
full header for the provided `TrustHeight` and then proceeds to download `N+1`
|
||||
headers and applies the [Tendermint validation
|
||||
rules](https://github.com/tendermint/tendermint/tree/main/spec/light-client/verification/README.md)
|
||||
rules](https://github.com/tendermint/tendermint/tree/v0.37.x/spec/light-client/verification/README.md)
|
||||
to each block.
|
||||
|
||||
### Bisecting Verification
|
||||
@@ -119,7 +119,7 @@ network usage.
|
||||
---
|
||||
|
||||
Check out the formal specification
|
||||
[here](https://github.com/tendermint/tendermint/tree/main/spec/light-client).
|
||||
[here](https://github.com/tendermint/tendermint/tree/v0.37.x/spec/light-client).
|
||||
|
||||
## Status
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ graceful here, but that's for another day.
|
||||
|
||||
It's possible to fool lite clients without there being a fork on the
|
||||
main chain - so called Fork-Lite. See the
|
||||
[fork accountability](https://github.com/tendermint/tendermint/blob/main/spec/light-client/accountability/README.md)
|
||||
[fork accountability](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/light-client/accountability/README.md)
|
||||
document for more details. For a sequential lite client, this can happen via
|
||||
equivocation or amnesia attacks. For a skipping lite client this can also happen
|
||||
via lunatic validator attacks. There must be some way for applications to punish
|
||||
@@ -31,7 +31,7 @@ checking).
|
||||
|
||||
Currently, evidence verification is handled by Tendermint. Once committed,
|
||||
[evidence is passed over
|
||||
ABCI](https://github.com/tendermint/tendermint/blob/main/proto/tendermint/abci/types.proto#L354)
|
||||
ABCI](https://github.com/tendermint/tendermint/blob/v0.37.x/proto/tendermint/abci/types.proto#L354)
|
||||
in BeginBlock in a reduced form that includes only
|
||||
the type of evidence, its height and timestamp, the validator it's from, and the
|
||||
total voting power of the validator set at the height. The app trusts Tendermint
|
||||
|
||||
@@ -179,13 +179,13 @@ This then ends the process and the verify function that was called at the start
|
||||
the user.
|
||||
|
||||
For a detailed overview of how each of these three attacks can be conducted please refer to the
|
||||
[fork accountability spec](https://github.com/tendermint/tendermint/blob/main/spec/consensus/light-client/accountability.md).
|
||||
[fork accountability spec](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/consensus/light-client/accountability.md).
|
||||
|
||||
## Full Node Verification
|
||||
|
||||
When a full node receives evidence from the light client it will need to verify
|
||||
it for itself before gossiping it to peers and trying to commit it on chain. This process is outlined
|
||||
in [ADR-059](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-059-evidence-composition-and-lifecycle.md).
|
||||
in [ADR-059](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-059-evidence-composition-and-lifecycle.md).
|
||||
|
||||
## Status
|
||||
|
||||
@@ -212,9 +212,9 @@ clear from the current information which nodes behaved maliciously.
|
||||
|
||||
## References
|
||||
|
||||
* [Fork accountability spec](https://github.com/tendermint/tendermint/blob/main/spec/consensus/light-client/accountability.md)
|
||||
* [ADR 056: Light client amnesia attacks](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-056-light-client-amnesia-attacks.md)
|
||||
* [ADR-059: Evidence Composition and Lifecycle](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-059-evidence-composition-and-lifecycle.md)
|
||||
* [Fork accountability spec](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/consensus/light-client/accountability.md)
|
||||
* [ADR 056: Light client amnesia attacks](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-056-light-client-amnesia-attacks.md)
|
||||
* [ADR-059: Evidence Composition and Lifecycle](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-059-evidence-composition-and-lifecycle.md)
|
||||
* [Informal's Light Client Detector](https://github.com/informalsystems/tendermint-rs/blob/master/docs/spec/lightclient/detection/detection.md)
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
## Context
|
||||
|
||||
Whilst most created evidence of malicious behavior is self evident such that any individual can verify them independently there are types of evidence, known collectively as global evidence, that require further collaboration from the network in order to accumulate enough information to create evidence that is individually verifiable and can therefore be processed through consensus. [Fork Accountability](https://github.com/tendermint/tendermint/blob/main/spec/consensus/light-client/accountability.md) has been coined to describe the entire process of detection, proving and punishing of malicious behavior. This ADR addresses specifically what a light client amnesia attack is and how it can be proven and the current decision around handling light client amnesia attacks. For information on evidence handling by the light client, it is recommended to read [ADR 47](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-047-handling-evidence-from-light-client.md).
|
||||
Whilst most created evidence of malicious behavior is self evident such that any individual can verify them independently there are types of evidence, known collectively as global evidence, that require further collaboration from the network in order to accumulate enough information to create evidence that is individually verifiable and can therefore be processed through consensus. [Fork Accountability](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/consensus/light-client/accountability.md) has been coined to describe the entire process of detection, proving and punishing of malicious behavior. This ADR addresses specifically what a light client amnesia attack is and how it can be proven and the current decision around handling light client amnesia attacks. For information on evidence handling by the light client, it is recommended to read [ADR 47](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-047-handling-evidence-from-light-client.md).
|
||||
|
||||
### Amnesia Attack
|
||||
|
||||
@@ -33,7 +33,7 @@ The decision surrounding amnesia attacks has both a short term and long term com
|
||||
|
||||
The latter of the two options meant storing a record of all votes in any height with which there was more than one round. This information would then be accessible for applications if they wanted to perform some off-chain verification and punishment.
|
||||
|
||||
In summary, this seemed like too much to ask of the application to implement only on a temporary basis, whilst not having the domain specific knowledge and considering such a difficult and unlikely attack. Therefore the short term decision is to identify when the attack has occurred and implement the detector algorithm highlighted in [ADR 47](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-047-handling-evidence-from-light-client.md) but to not implement any accountability protocol that would identify malicious validators and allow applications to punish them. This will hopefully change in the long term with the focus on eventually reaching a concrete and secure protocol with identifying and dealing with these attacks.
|
||||
In summary, this seemed like too much to ask of the application to implement only on a temporary basis, whilst not having the dov0.37.x specific knowledge and considering such a difficult and unlikely attack. Therefore the short term decision is to identify when the attack has occurred and implement the detector algorithm highlighted in [ADR 47](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-047-handling-evidence-from-light-client.md) but to not implement any accountability protocol that would identify malicious validators and allow applications to punish them. This will hopefully change in the long term with the focus on eventually reaching a concrete and secure protocol with identifying and dealing with these attacks.
|
||||
|
||||
## Implications
|
||||
|
||||
@@ -63,9 +63,9 @@ Light clients where all witnesses are faulty can be subject to an amnesia attack
|
||||
|
||||
|
||||
## References
|
||||
<!-- markdown-link-check-disable-next-line -->
|
||||
|
||||
- [Fork accountability algorithm](https://docs.google.com/document/d/11ZhMsCj3y7zIZz4udO9l25xqb0kl7gmWqNpGVRzOeyY/edit)
|
||||
- [Fork accountability spec](https://github.com/tendermint/tendermint/blob/main/spec/consensus/light-client/accountability.md)
|
||||
- [Fork accountability spec](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/consensus/light-client/accountability.md)
|
||||
|
||||
## Appendix A: Detailed Walkthrough of Performing a Light Client Amnesia Attack
|
||||
|
||||
@@ -107,7 +107,7 @@ As the distinction between these two attacks (amnesia and back to the past) can
|
||||
|
||||
Currently, the evidence reactor is used to simply broadcast and store evidence. The idea of creating a new reactor for the specific task of verifying these attacks was briefly discussed, but it is decided that the current evidence reactor will be extended.
|
||||
|
||||
The process begins with a light client receiving conflicting headers (in the future this could also be a full node during fast sync or state sync), which it sends to a full node to analyze. As part of [evidence handling](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-047-handling-evidence-from-light-client.md), this is extracted into potential amnesia evidence when the validator voted in more than one round for a different block.
|
||||
The process begins with a light client receiving conflicting headers (in the future this could also be a full node during fast sync or state sync), which it sends to a full node to analyze. As part of [evidence handling](https://github.com/tendermint/tendermint/blob/v0.37.x/docs/architecture/adr-047-handling-evidence-from-light-client.md), this is extracted into potential amnesia evidence when the validator voted in more than one round for a different block.
|
||||
|
||||
```golang
|
||||
type PotentialAmnesiaEvidence struct {
|
||||
@@ -128,7 +128,7 @@ This trial period will be discussed later.
|
||||
|
||||
Returning to the event of an amnesia attack, if we were to examine the behavior of the honest nodes, C1 and C2, in the schematic, C2 will not PRECOMMIT an earlier round, but it is likely, if a node in C1 were to receive +2/3 PREVOTE's or PRECOMMIT's for a higher round, that it would remove the lock and PREVOTE and PRECOMMIT for the later round. Therefore, unfortunately it is not a case of simply punishing all nodes that have double voted in the `PotentialAmnesiaEvidence`.
|
||||
|
||||
Instead we use the Proof of Lock Change (PoLC) referred to in the [consensus spec](https://github.com/tendermint/tendermint/blob/main/spec/consensus/consensus.md#terms). When an honest node votes again for a different block in a later round
|
||||
Instead we use the Proof of Lock Change (PoLC) referred to in the [consensus spec](https://github.com/tendermint/tendermint/blob/v0.37.x/spec/consensus/consensus.md#terms). When an honest node votes again for a different block in a later round
|
||||
(which will only occur in very rare cases), it will generate the PoLC and store it in the evidence reactor for a time equal to the `MaxEvidenceAge`
|
||||
|
||||
```golang
|
||||
|
||||
@@ -162,7 +162,7 @@ The API guarantees above can be fairly constraining, but are unavoidable given t
|
||||
|
||||
## Status
|
||||
|
||||
Proposed
|
||||
Accepted
|
||||
|
||||
## Consequences
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user