Compare commits

...

335 Commits

Author SHA1 Message Date
Callum Waters
e6925d5dff create valset-change tool 2022-10-07 11:38:52 +02:00
mmsqe
5c23ffb05b Remove the PEG query implementation. (#7336) (#9478) 2022-10-04 11:03:03 +02:00
dependabot[bot]
45518db3d0 build(deps): Bump styfle/cancel-workflow-action from 0.10.0 to 0.10.1 (#9501)
Bumps [styfle/cancel-workflow-action](https://github.com/styfle/cancel-workflow-action) from 0.10.0 to 0.10.1.
- [Release notes](https://github.com/styfle/cancel-workflow-action/releases)
- [Commits](https://github.com/styfle/cancel-workflow-action/compare/0.10.0...0.10.1)

---
updated-dependencies:
- dependency-name: styfle/cancel-workflow-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-03 11:03:48 +02:00
Thane Thomson
f76f6535b4 ci: Only notify on nightly E2E failures (#9495)
Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-09-28 10:07:06 -04:00
dependabot[bot]
20ffe9e101 build(deps): Bump actions/stale from 5 to 6 (#9493)
Bumps [actions/stale](https://github.com/actions/stale) from 5 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/actions/stale/releases">actions/stale's releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<p>⚠️ Breaking change ⚠️</p>
<p>Issues/PRs default <code>close-issue-reason</code> is now <code>not_planned</code>(<a href="https://github-redirect.dependabot.com/actions/stale/issues/789">#789</a>)</p>
<h2>V5.2.0</h2>
<p>Features:
New option <code>include-only-assigned</code> enables users to process only issues/PRs that are already assigned. If there is no assignees and this option is set, issue will not be processed per: <a href="https://github-redirect.dependabot.com/actions/stale/issues/596">issue/596</a></p>
<p>Fixes:
Fix date comparison edge case <a href="https://github-redirect.dependabot.com/actions/stale/pull/816">PR/816</a></p>
<p>Dependency Updates:
<a href="https://github-redirect.dependabot.com/actions/stale/pull/812">PR/812</a></p>
<h2>Fix issue when days-before-close is more than days-before-stale</h2>
<p>fixes a bug introduced in <a href="https://github-redirect.dependabot.com/actions/stale/issues/717">#717</a></p>
<p>fixed in <a href="https://github-redirect.dependabot.com/actions/stale/issues/775">#775</a></p>
<h2>v5.1.0</h2>
<h1>[5.1.0]</h1>
<p><a href="https://github-redirect.dependabot.com/actions/stale/issues/696">Don't process stale issues right after they're marked stale</a>
Add close-issue-reason option <a href="https://github-redirect.dependabot.com/actions/stale/pull/764">#764</a><a href="https://github-redirect.dependabot.com/actions/stale/pull/772">#772</a>
Various dependabot/dependency updates</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/actions/stale/blob/main/CHANGELOG.md">actions/stale's changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h1>[6.0.0]</h1>
<p>⚠️ Breaking change ⚠️</p>
<p>Issues/PRs default <code>close-issue-reason</code> is now <code>not_planned</code>(<a href="https://github-redirect.dependabot.com/actions/stale/issues/789">#789</a>)</p>
<h1>[5.1.0]</h1>
<p><a href="https://github-redirect.dependabot.com/actions/stale/issues/696">Don't process stale issues right after they're marked stale</a>
[Add close-issue-reason option]<a href="https://github-redirect.dependabot.com/actions/stale/pull/764">#764</a><a href="https://github-redirect.dependabot.com/actions/stale/pull/772">#772</a>
Various dependabot/dependency updates</p>
<h2><a href="https://github.com/actions/stale/compare/v3.0.19...v4.1.0">4.1.0</a> (2021-07-14)</h2>
<h2>Features</h2>
<ul>
<li><a href="9912fa74d1">Ability to exempt draft PRs</a></li>
</ul>
<h2><a href="https://github.com/actions/stale/compare/v3.0.19...v4.0.0">4.0.0</a> (2021-07-14)</h2>
<h3>Features</h3>
<ul>
<li><strong>options:</strong> simplify config by removing skip stale message options (<a href="https://github-redirect.dependabot.com/actions/stale/issues/457">#457</a>) (<a href="6ec637d238">6ec637d</a>), closes <a href="https://github-redirect.dependabot.com/actions/stale/issues/405">#405</a> <a href="https://github-redirect.dependabot.com/actions/stale/issues/455">#455</a></li>
<li><strong>output:</strong> print output parameters (<a href="https://github-redirect.dependabot.com/actions/stale/issues/458">#458</a>) (<a href="3e6d35b685">3e6d35b</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>dry-run:</strong> forbid mutations in dry-run (<a href="https://github-redirect.dependabot.com/actions/stale/issues/500">#500</a>) (<a href="f1017f33dd">f1017f3</a>), closes <a href="https://github-redirect.dependabot.com/actions/stale/issues/499">#499</a></li>
<li><strong>logs:</strong> coloured logs (<a href="https://github-redirect.dependabot.com/actions/stale/issues/465">#465</a>) (<a href="5fbbfba142">5fbbfba</a>)</li>
<li><strong>operations:</strong> fail fast the current batch to respect the operations limit (<a href="https://github-redirect.dependabot.com/actions/stale/issues/474">#474</a>) (<a href="5f6f311ca6">5f6f311</a>), closes <a href="https://github-redirect.dependabot.com/actions/stale/issues/466">#466</a></li>
<li><strong>label comparison</strong>: make label comparison case insensitive <a href="https://github-redirect.dependabot.com/actions/stale/pull/517">#517</a>, closes <a href="https://github-redirect.dependabot.com/actions/stale/pull/516">#516</a></li>
<li><strong>filtering comments by actor could have strange behavior</strong>: &quot;stale&quot; comments are now detected based on if the message is the stale message not <em>who</em> made the comment(<a href="https://github-redirect.dependabot.com/actions/stale/pull/519">#519</a>), fixes <a href="https://github-redirect.dependabot.com/actions/stale/pull/441">#441</a>, <a href="https://github-redirect.dependabot.com/actions/stale/pull/509">#509</a>, <a href="https://github-redirect.dependabot.com/actions/stale/pull/518">#518</a></li>
</ul>
<h3>Breaking Changes</h3>
<ul>
<li>The options <code>skip-stale-issue-message</code> and <code>skip-stale-pr-message</code> were removed. Instead, setting the options <code>stale-issue-message</code> and <code>stale-pr-message</code> will be enough to let the stale workflow add a comment. If the options are unset, a comment will not be added which was the equivalent of setting <code>skip-stale-issue-message</code> to <code>true</code>.</li>
<li>The <code>operations-per-run</code> option will be more effective. After migrating, you could face a failed-fast process workflow if you let the default value (30) or set it to a small number. In that case, you will see a warning at the end of the logs (if enabled) indicating that the workflow was stopped sooner to avoid consuming too much API calls. In most cases, you can just increase this limit to make sure to process everything in a single run.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="3de2653986"><code>3de2653</code></a> Update changelog for v6.0.0 (<a href="https://github-redirect.dependabot.com/actions/stale/issues/829">#829</a>)</li>
<li><a href="02e44c81cc"><code>02e44c8</code></a> fix(options)!: Make <code>not_planned</code> the default <code>close-issue-reason</code> (<a href="https://github-redirect.dependabot.com/actions/stale/issues/807">#807</a>)</li>
<li>See full diff in <a href="https://github.com/actions/stale/compare/v5...v6">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/stale&package-manager=github_actions&previous-version=5&new-version=6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-09-27 15:51:22 +00:00
Callum Waters
af5281d704 statesync: convert snapshot hashes to hex strings for logging (#9471) 2022-09-26 17:58:52 +02:00
Emmanuel T Odeke
ed68aadd2b .github/workflows: add cosmos/gosec vulnerability scanner for each Push/PR (#9464)
Adds a code vulnerability scanner that'll flag issues and issue advisories from cosmos/gosec https://github.com/cosmos/gosec
2022-09-23 20:26:55 +00:00
JayT106
e8ec611ed4 tools: use os home dir to instead of the hardcoded PATH (#9444)
porting PR #6498 to main

#### PR checklist

- [x] Tests written/updated, or no tests needed
- [x] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [x] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-23 20:15:19 +00:00
William Banfield
5fe1a72416 loadtime: add block time to the data point (#9484)
This pull request adds the block time as the unix time since the epoch to the `report` tool's csv output.

```csv
...
a7a8b903-1136-4da1-97aa-d25da7b4094f,1614226790,1663707084905417366,4,200,1024
a7a8b903-1136-4da1-97aa-d25da7b4094f,1614196724,1663707084905417366,4,200,1024
a7a8b903-1136-4da1-97aa-d25da7b4094f,1613097336,1663707084905417366,4,200,1024
a7a8b903-1136-4da1-97aa-d25da7b4094f,1609365168,1663707084905417366,4,200,1024
a7a8b903-1136-4da1-97aa-d25da7b4094f,1617199169,1663707084905417366,4,200,1024
a7a8b903-1136-4da1-97aa-d25da7b4094f,1615197134,1663707084905417366,4,200,1024
a7a8b903-1136-4da1-97aa-d25da7b4094f,1610399447,1663707084905417366,4,200,1024
...
```

#### PR checklist

- [ ] Tests written/updated, or no tests needed
- [ ] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [ ] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-23 13:55:55 +00:00
Thane Thomson
b7f1e1f218 config: Add missing storage section when generating config (#9483) 2022-09-23 12:19:49 +02:00
Callum Waters
a0ed437942 config: cleaner separation of tests (#9421) 2022-09-22 12:42:25 +02:00
Callum Waters
561440a56d config: add version to the config file (#9413) 2022-09-22 10:49:31 +02:00
Thane Thomson
f1dc5811c3 Sync Vote.Verify() in spec with implementation (#9466) 2022-09-21 21:29:24 -04:00
Thane Thomson
e48d5a0294 docs: Use release badge in README instead of latest tag (#9475)
[Rendered](https://github.com/tendermint/tendermint/blob/thane/readme-release-badge/README.md)

The release tag currently shows `dev-v0.38.0`, which isn't useful to anyone.

---

#### PR checklist

- [x] Tests written/updated, or no tests needed
- [x] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [x] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-21 21:50:18 +00:00
William Banfield
f2c32c9b3e metrics: fix panic because of absent prometheus label (#9455)
Absence of this label causes a panic because the setters try to access the label despite it never being added to the metric. This PR adds the label to the metrics, thus preventing the panic.

#### PR checklist

- [ ] Tests written/updated, or no tests needed
- [ ] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [ ] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-21 17:07:07 +00:00
Mark Rushakoff
84bc77cb1f Ensure Dockerfile stages use consistent Go version (#9462)
I noticed the tendermint image was running on Go 1.15. I assume that was just a missed search and replace when updating to go1.18.

Pull the go base image into a build arg so that the image is only defined once, and used consistently across all stages of the build.

#### PR checklist

- [x] Tests written/updated, or no tests needed
- [x] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [x] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-21 13:12:32 +00:00
Sergio Mena
fbcfecbc3a fix spec (#9467) 2022-09-21 14:33:29 +02:00
JayT106
fe0aa4d30e Normalise GenesisDoc before saving to state (#6059) (#9458) 2022-09-21 11:06:13 +02:00
JayT106
080dfab992 p2p/pex: reuse hash.Hasher per addrbook for speed (#6509) (#9445)
Cherry-picking PR #6509

By pre-creating the hasher, instead of creating new one everytime addrbook.hash is called.

```
name             old time/op    new time/op    delta
AddrBook_hash-8     181ns ±13%      80ns ± 1%  -56.08%  (p=0.000 n=10+10)

name             old alloc/op   new alloc/op   delta
AddrBook_hash-8      216B ± 0%        8B ± 0%  -96.30%  (p=0.000 n=10+10)

name             old allocs/op  new allocs/op  delta
AddrBook_hash-8      2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=10+10)
```

Fixed #6508



---

#### PR checklist

- [x] Tests written/updated, or no tests needed
- [x] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [x] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-21 08:34:14 +00:00
JayT106
ab4238a0e2 crypto/merkle: optimize merkle tree hashing (#6513) (#9446)
* crypto/merkle: optimize merkle tree hashing (#6513)

Upstream https://github.com/lazyledger/lazyledger-core/pull/351 to optimize merkle tree hashing

```
benchmark                                 old ns/op     new ns/op     delta
BenchmarkHashAlternatives/recursive-8     22914         21949         -4.21%
BenchmarkHashAlternatives/iterative-8     21634         21939         +1.41%

benchmark                                 old allocs     new allocs     delta
BenchmarkHashAlternatives/recursive-8     398            200            -49.75%
BenchmarkHashAlternatives/iterative-8     399            301            -24.56%

benchmark                                 old bytes     new bytes     delta
BenchmarkHashAlternatives/recursive-8     19088         6496          -65.97%
BenchmarkHashAlternatives/iterative-8     21776         13984         -35.78%
```

cc @odeke-em @cuonglm

* update pending log

Co-authored-by: Marko <marbar3778@yahoo.com>
2022-09-21 10:18:05 +02:00
JayT106
bfdeccd649 crypto/merkle: pre-allocate data slice in innherHash (#6443) (#9447)
Cherry-picking PR #6443

#### PR checklist

- [x] Tests written/updated, or no tests needed
- [x] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [x] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-21 08:00:53 +00:00
Callum Waters
e84d43ec93 cli: add --hard flag to rollback command to remove block as well (#9261)
Co-authored-by: Levi Aul <levi@leviaul.com>
2022-09-21 09:51:22 +02:00
Yawning Angel
2d1ada4d52 crypto: Upstream v0.35.x improvements (#9255)
* crypto: Use curve25519-voi

This switches the ed25519, sr25519 and merlin provider to curve25519-voi
and additionally adopts ZIP-215 semantics for ed25519 verification.

* crypto: Implement batch verification interface for ed25519 and sr25519

This commit adds the batch verification interface, but does not enable
it for anything.

* types: Use batch verification for verifying commits signatures
2022-09-21 09:34:04 +02:00
dependabot[bot]
c69ab68848 build(deps): Bump github.com/cosmos/gogoproto from 1.4.1 to 1.4.2 (#9451)
Bumps [github.com/cosmos/gogoproto](https://github.com/cosmos/gogoproto) from 1.4.1 to 1.4.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/cosmos/gogoproto/releases">github.com/cosmos/gogoproto's releases</a>.</em></p>
<blockquote>
<h2>v1.4.2</h2>
<h3>Features</h3>
<ul>
<li><a href="https://github-redirect.dependabot.com/cosmos/gogoproto/pull/13">#13</a> Add <code>AllFileDescriptors</code> function.</li>
</ul>
<h3>Improvements</h3>
<ul>
<li><a href="https://github-redirect.dependabot.com/cosmos/gogoproto/pull/8">#8</a> Fix typo in <code>doc.go</code>.</li>
<li><a href="https://github-redirect.dependabot.com/cosmos/gogoproto/pull/8">#8</a> Support for merging messages implementing Merger which are embedded by value.</li>
<li><a href="https://github-redirect.dependabot.com/cosmos/gogoproto/pull/8">#8</a> Use reflect.Value.String() for String kinds in proto equal.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/cosmos/gogoproto/blob/main/CHANGELOG.md">github.com/cosmos/gogoproto's changelog</a>.</em></p>
<blockquote>
<h2><a href="https://github.com/cosmos/gogoproto/releases/tag/v1.4.2">v1.4.2</a> - 2022-09-14</h2>
<h3>Features</h3>
<ul>
<li><a href="https://github-redirect.dependabot.com/cosmos/gogoproto/pull/13">#13</a> Add <code>AllFileDescriptors</code> function.</li>
</ul>
<h3>Improvements</h3>
<ul>
<li><a href="https://github-redirect.dependabot.com/cosmos/gogoproto/pull/8">#8</a> Fix typo in <code>doc.go</code>.</li>
<li><a href="https://github-redirect.dependabot.com/cosmos/gogoproto/pull/8">#8</a> Support for merging messages implementing Merger which are embedded by value.</li>
<li><a href="https://github-redirect.dependabot.com/cosmos/gogoproto/pull/8">#8</a> Use reflect.Value.String() for String kinds in proto equal.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="739310d858"><code>739310d</code></a> docs: add changelog (<a href="https://github-redirect.dependabot.com/cosmos/gogoproto/issues/15">#15</a>)</li>
<li><a href="4f8afe8bcd"><code>4f8afe8</code></a> feat: add AllFileDescriptors function (<a href="https://github-redirect.dependabot.com/cosmos/gogoproto/issues/13">#13</a>)</li>
<li><a href="27e5769808"><code>27e5769</code></a> ci: fix proto registry workflow (<a href="https://github-redirect.dependabot.com/cosmos/gogoproto/issues/12">#12</a>)</li>
<li><a href="c3a0399b5e"><code>c3a0399</code></a> feat: cherry-pick improvements from <code>gogo/protobuf</code> (<a href="https://github-redirect.dependabot.com/cosmos/gogoproto/issues/8">#8</a>)</li>
<li><a href="ed9594ccc9"><code>ed9594c</code></a> chore: bump protobuf (<a href="https://github-redirect.dependabot.com/cosmos/gogoproto/issues/9">#9</a>)</li>
<li>See full diff in <a href="https://github.com/cosmos/gogoproto/compare/v1.4.1...v1.4.2">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/cosmos/gogoproto&package-manager=go_modules&previous-version=1.4.1&new-version=1.4.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-09-20 14:30:18 +00:00
dependabot[bot]
10d1156add build(deps): Bump github.com/bufbuild/buf from 1.7.0 to 1.8.0 (#9452)
Bumps [github.com/bufbuild/buf](https://github.com/bufbuild/buf) from 1.7.0 to 1.8.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/bufbuild/buf/releases">github.com/bufbuild/buf's releases</a>.</em></p>
<blockquote>
<h2>v1.8.0</h2>
<ul>
<li>Change default for <code>--origin</code> flag of <code>buf beta studio-agent</code> to <code>https://studio.buf.build</code></li>
<li>Change default for <code>--timeout</code> flag of <code>buf beta studio-agent</code> to <code>0</code> (no timeout). Before it was
<code>2m</code> (the default for all the other <code>buf</code> commands).</li>
<li>Add support for experimental code generation with the <code>plugin:</code> key in <code>buf.gen.yaml</code>.</li>
<li>Preserve single quotes with <code>buf format</code>.</li>
<li>Support <code>junit</code> format errors with <code>--error-format</code>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/bufbuild/buf/blob/main/CHANGELOG.md">github.com/bufbuild/buf's changelog</a>.</em></p>
<blockquote>
<h2>[v1.8.0] - 2022-09-14</h2>
<ul>
<li>Change default for <code>--origin</code> flag of <code>buf beta studio-agent</code> to <code>https://studio.buf.build</code></li>
<li>Change default for <code>--timeout</code> flag of <code>buf beta studio-agent</code> to <code>0</code> (no timeout). Before it was
<code>2m</code> (the default for all the other <code>buf</code> commands).</li>
<li>Add support for experimental code generation with the <code>plugin:</code> key in <code>buf.gen.yaml</code>.</li>
<li>Preserve single quotes with <code>buf format</code>.</li>
<li>Support <code>junit</code> format errors with <code>--error-format</code>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="dbd4a13a08"><code>dbd4a13</code></a> Update to v1.8.0</li>
<li><a href="4ab9fb1d82"><code>4ab9fb1</code></a> Add <code>LimitWriteBucket</code> (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1390">#1390</a>)</li>
<li><a href="95670a74cb"><code>95670a7</code></a> Rename repo member to contributor (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1402">#1402</a>)</li>
<li><a href="57e6293dda"><code>57e6293</code></a> fix comment to reference new command name (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1401">#1401</a>)</li>
<li><a href="382276c38e"><code>382276c</code></a> add httpserver.Run function (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1397">#1397</a>)</li>
<li><a href="f3fe91a9c0"><code>f3fe91a</code></a> fix local generation using plugin key (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1399">#1399</a>)</li>
<li><a href="59abf7924b"><code>59abf79</code></a> BSR-527 - Adds old visibility to repository visiblity changed event. (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1398">#1398</a>)</li>
<li><a href="0f5d198dac"><code>0f5d198</code></a> BSR-527 - Adds <code>PayloadRepositoryVisibilityChanged</code> (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1395">#1395</a>)</li>
<li><a href="5da7dc20c2"><code>5da7dc2</code></a> Add curated plugin search term (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1394">#1394</a>)</li>
<li><a href="495c5912fb"><code>495c591</code></a> implement protocol for negotiating supported features with plugin (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1360">#1360</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/bufbuild/buf/compare/v1.7.0...v1.8.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/bufbuild/buf&package-manager=go_modules&previous-version=1.7.0&new-version=1.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-09-20 13:20:05 +00:00
dependabot[bot]
0f857047c5 build(deps): Bump bufbuild/buf-setup-action from 1.7.0 to 1.8.0 (#9450)
Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.7.0 to 1.8.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/bufbuild/buf-setup-action/releases">bufbuild/buf-setup-action's releases</a>.</em></p>
<blockquote>
<h2>v1.8.0</h2>
<ul>
<li>Set the default buf version to v1.8.0</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="ebfad693a1"><code>ebfad69</code></a> Update to v1.8.0</li>
<li><a href="9da1a4b683"><code>9da1a4b</code></a> upgrade dependencies (<a href="https://github-redirect.dependabot.com/bufbuild/buf-setup-action/issues/58">#58</a>)</li>
<li>See full diff in <a href="https://github.com/bufbuild/buf-setup-action/compare/v1.7.0...v1.8.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=bufbuild/buf-setup-action&package-manager=github_actions&previous-version=1.7.0&new-version=1.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-09-20 13:05:28 +00:00
JayT106
db26cff58f state: move pruneBlocks from consensus/state to state/execution (#9443) 2022-09-20 11:30:22 +02:00
William Banfield
a8efef1854 rfc: simplify mempool to support more broad tendermint uses (#9294)
For: #9240 

📖 [Rendered](https://github.com/tendermint/tendermint/blob/wb/app-side-mempool/docs/rfc/rfc-025-support-app-side-mempool.md)

#### PR checklist

- [ ] Tests written/updated, or no tests needed
- [ ] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [ ] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-19 21:23:46 +00:00
Callum Waters
21a3bbda3f state: restore previous error message (#9435) 2022-09-16 14:49:51 +02:00
Thane Thomson
0c96f0b434 docs: Remove dev base tagging from release branch creation (#9434)
Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-09-15 09:15:12 -04:00
Thane Thomson
3293ce6f94 docs: Enable build for v0.37.x branch (#9433) 2022-09-13 19:12:48 -04:00
dependabot[bot]
d67be51ef4 build(deps): Bump slackapi/slack-github-action from 1.21.0 to 1.22.0 (#9431)
Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.21.0 to 1.22.0.
- [Release notes](https://github.com/slackapi/slack-github-action/releases)
- [Commits](https://github.com/slackapi/slack-github-action/compare/v1.21.0...v1.22.0)

---
updated-dependencies:
- dependency-name: slackapi/slack-github-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-13 16:53:17 -04:00
Thane Thomson
10f3626e6f ci: Only allow automated security-related updates until v0.37.0 release (#9430)
As per discussion with @sergio-mena, this should disable all automated
dependency updates that are not security-related. We should make this
part of our standard practice when cutting new major releases, given
that our QA process for major releases is expensive at present and we
cannot re-run it for every dependency update.

Once we have cut a final major release, we can consider re-enabling
automated dependency updates here that can be rolled out in minor
releases.

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-09-13 16:46:34 -04:00
dependabot[bot]
7bd84cd8cc build(deps): Bump github.com/gofrs/uuid (#9406)
Bumps [github.com/gofrs/uuid](https://github.com/gofrs/uuid) from 4.2.0+incompatible to 4.3.0+incompatible.
- [Release notes](https://github.com/gofrs/uuid/releases)
- [Commits](https://github.com/gofrs/uuid/compare/v4.2.0...v4.3.0)

---
updated-dependencies:
- dependency-name: github.com/gofrs/uuid
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-13 16:31:30 -04:00
dependabot[bot]
7feb484765 build(deps): Bump gonum.org/v1/gonum from 0.8.2 to 0.12.0 (#9407)
Bumps gonum.org/v1/gonum from 0.8.2 to 0.12.0.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=gonum.org/v1/gonum&package-manager=go_modules&previous-version=0.8.2&new-version=0.12.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-09-13 14:25:37 +00:00
dependabot[bot]
2d77374d4f build(deps): Bump github.com/lib/pq from 1.10.6 to 1.10.7 (#9405)
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.6 to 1.10.7.
<details>
<summary>Commits</summary>
<ul>
<li><a href="d5affd5073"><code>d5affd5</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/lib/pq/issues/1088">#1088</a> from kelvich/sni_support</li>
<li><a href="d65e6ae4bd"><code>d65e6ae</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/lib/pq/issues/1083">#1083</a> from nhooyr/fix-receiver-51e2</li>
<li><a href="957fc0b401"><code>957fc0b</code></a> Set SNI for TSL connections</li>
<li><a href="89fee89644"><code>89fee89</code></a> Use pointer receiver on pq.Error.Error()</li>
<li>See full diff in <a href="https://github.com/lib/pq/compare/v1.10.6...v1.10.7">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/lib/pq&package-manager=go_modules&previous-version=1.10.6&new-version=1.10.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-09-13 13:07:15 +00:00
dependabot[bot]
c1f163f39b build(deps): Bump github.com/spf13/viper from 1.12.0 to 1.13.0 (#9408)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.12.0 to 1.13.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/spf13/viper/releases">github.com/spf13/viper's releases</a>.</em></p>
<blockquote>
<h2>v1.13.0</h2>
<p><strong>Important:</strong> This is the last release supporting Go 1.15.</p>
<h2>What's Changed</h2>
<h3>Exciting New Features 🎉</h3>
<ul>
<li>Add etcd3 to supported remote providers by <a href="https://github.com/franklinkim"><code>@​franklinkim</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1371">spf13/viper#1371</a></li>
</ul>
<h3>Enhancements 🚀</h3>
<ul>
<li>Fix go-staticcheck failures (ST1005) by <a href="https://github.com/mjmaisey"><code>@​mjmaisey</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1373">spf13/viper#1373</a></li>
<li>Use jsonc in markdown codeblocks for better readability by <a href="https://github.com/HurSungYun"><code>@​HurSungYun</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1393">spf13/viper#1393</a></li>
<li>Add Go 1.19 support by <a href="https://github.com/sagikazarmark"><code>@​sagikazarmark</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1424">spf13/viper#1424</a></li>
<li>Adds support for uint16 with <code>GetUint16</code> by <a href="https://github.com/oxisto"><code>@​oxisto</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1405">spf13/viper#1405</a></li>
<li>Add a DebugTo convenience funtion by <a href="https://github.com/bcrochet"><code>@​bcrochet</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1414">spf13/viper#1414</a></li>
</ul>
<h3>Bug Fixes 🐛</h3>
<ul>
<li>Recurse into arrays when converting keys to lowercase by <a href="https://github.com/awrichar"><code>@​awrichar</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1387">spf13/viper#1387</a></li>
</ul>
<h3>Dependency Updates ⬆️</h3>
<ul>
<li>build(deps): bump github.com/stretchr/testify from 1.7.1 to 1.7.2 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1374">spf13/viper#1374</a></li>
<li>build(deps): bump github.com/subosito/gotenv from 1.3.0 to 1.4.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1375">spf13/viper#1375</a></li>
<li>build(deps): bump github.com/pelletier/go-toml/v2 from 2.0.1 to 2.0.2 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1378">spf13/viper#1378</a></li>
<li>build(deps): bump gopkg.in/yaml.v3 from 3.0.0 to 3.0.1 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1360">spf13/viper#1360</a></li>
<li>build(deps): bump github.com/stretchr/testify from 1.7.2 to 1.7.3 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1381">spf13/viper#1381</a></li>
<li>build(deps): bump github.com/stretchr/testify from 1.7.3 to 1.7.4 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1384">spf13/viper#1384</a></li>
<li>build(deps): bump mheap/github-action-required-labels from 1 to 2 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1383">spf13/viper#1383</a></li>
<li>build(deps): bump github.com/stretchr/testify from 1.7.4 to 1.8.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1395">spf13/viper#1395</a></li>
<li>build(deps): bump github.com/subosito/gotenv from 1.4.0 to 1.4.1 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1420">spf13/viper#1420</a></li>
<li>build(deps): bump github.com/pelletier/go-toml/v2 from 2.0.2 to 2.0.5 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1422">spf13/viper#1422</a></li>
<li>build(deps): bump gopkg.in/ini.v1 from 1.66.4 to 1.67.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1412">spf13/viper#1412</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/mjmaisey"><code>@​mjmaisey</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1373">spf13/viper#1373</a></li>
<li><a href="https://github.com/HurSungYun"><code>@​HurSungYun</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1393">spf13/viper#1393</a></li>
<li><a href="https://github.com/franklinkim"><code>@​franklinkim</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1371">spf13/viper#1371</a></li>
<li><a href="https://github.com/awrichar"><code>@​awrichar</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1387">spf13/viper#1387</a></li>
<li><a href="https://github.com/oxisto"><code>@​oxisto</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1405">spf13/viper#1405</a></li>
<li><a href="https://github.com/bcrochet"><code>@​bcrochet</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/spf13/viper/pull/1414">spf13/viper#1414</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/spf13/viper/compare/v1.12.0...v1.13.0">https://github.com/spf13/viper/compare/v1.12.0...v1.13.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="57cc9a000f"><code>57cc9a0</code></a> test: fix ini tests</li>
<li><a href="8030d5b976"><code>8030d5b</code></a> build(deps): bump gopkg.in/ini.v1 from 1.66.4 to 1.67.0</li>
<li><a href="312417a0c5"><code>312417a</code></a> Add a DebugTo convenience funtion</li>
<li><a href="202060b3a2"><code>202060b</code></a> Adds support for uint16 with <code>GetUint16</code></li>
<li><a href="97591f0083"><code>97591f0</code></a> build: fix lint violations</li>
<li><a href="9af8daeeab"><code>9af8dae</code></a> ci: upgrade golangci-lint</li>
<li><a href="7b4f2b27cd"><code>7b4f2b2</code></a> ci: add Go 1.19 to CI</li>
<li><a href="601ec815ba"><code>601ec81</code></a> test: fix toml tests</li>
<li><a href="d7f4832bd3"><code>d7f4832</code></a> build(deps): bump github.com/pelletier/go-toml/v2 from 2.0.2 to 2.0.5</li>
<li><a href="c2f42f3060"><code>c2f42f3</code></a> build(deps): bump github.com/subosito/gotenv from 1.4.0 to 1.4.1</li>
<li>Additional commits viewable in <a href="https://github.com/spf13/viper/compare/v1.12.0...v1.13.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/spf13/viper&package-manager=go_modules&previous-version=1.12.0&new-version=1.13.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-09-13 09:29:58 +00:00
mmsqe
e80dd00894 backport: performance improvements for the event query API (#7319) (#9334)
* Performance improvements for the event query API (#7319)

Rework the implementation of event query parsing and execution to
improve performance and reduce memory usage.

Previous memory and CPU profiles of the pubsub service showed query
processing as a significant hotspot. While we don't have evidence that
this is visibly hurting users, fixing it is fairly easy and self-contained.

Updates #6439.

Typical benchmark results comparing the original implementation (PEG) with the reworked implementation (Custom):
```
TEST                        TIME/OP  BYTES/OP  ALLOCS/OP  SPEEDUP   MEM SAVING
BenchmarkParsePEG-12       51716 ns  526832    27
BenchmarkParseCustom-12     2167 ns    4616    17         23.8x     99.1%
BenchmarkMatchPEG-12        3086 ns    1097    22
BenchmarkMatchCustom-12    294.2 ns      64     3         10.5x     94.1%
```
2022-09-13 10:42:14 +02:00
Callum Waters
93ead3d0e5 remove fast sync deprecation warning (#9414) 2022-09-13 10:18:52 +02:00
Riccardo Montagnin
8e90d294ca feat: support HTTPS inside websocket (#9416) 2022-09-13 10:02:19 +02:00
Thane Thomson
dfefd837e7 docs: Update ADRs for v0.37 (#9399)
* ADR-060 accepted -> proposed

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ADR-061 accepted -> proposed

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ADR-062 implemented -> proposed

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ADR-063 implemented -> accepted

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ADR-077: Update title and status to reflect current reality

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ADR-078: Update status to reflect current reality

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ADR-079: accepted

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ADR-068 and ADR-080: proposed

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ADR-065: implemented

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ADR-076: implemented

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-09-12 07:23:11 -04:00
Elias Naur
ac866e38d4 test/fuzz: bring changes from v0.34.x into main (#9299) 2022-09-11 16:27:42 +02:00
Wachiu Siu
0f45086c5f update btcec to v2 and use the latest btcutil (#9250)
* secp256k1: upgrade to latest btcec v2 and btcutil

* Update CHANGELOG_PENDING.md

Co-authored-by: Thane Thomson <connect@thanethomson.com>

* fix rebase

Co-authored-by: Thane Thomson <connect@thanethomson.com>
2022-09-09 07:32:23 -04:00
samricotta
5013bc3f4a Update to markdown links (#9384)
* first correction of markdown links

* Review updates
2022-09-08 10:31:35 +02:00
William Banfield
59a711eabe test: generate uuid on startup for load tool (#9383)
the `NewClient` method is called by the load test framework for each connection. This means that if multiple connections are instantiated, each connection will erroneously have its own UUID. This PR changes the UUID generation to happen at the _beginning_ of the script instead of on client creation so that each experimental run shares a UUID.

Caught while preparing the script for production readiness.

#### PR checklist

- [ ] Tests written/updated, or no tests needed
- [ ] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [ ] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-08 01:00:07 +00:00
samricotta
43ebbed9c2 add redirect links (#9385) 2022-09-07 09:27:48 -04:00
Marko
ffce253273 print all versions of tendermint and its sub protocols (#9329) 2022-09-07 14:32:56 +02:00
Callum Waters
2ae117ef62 config: fix broken test (#9309) 2022-09-07 11:42:20 +02:00
dependabot[bot]
1944dfd873 build(deps): Bump gonum.org/v1/gonum from 0.11.0 to 0.12.0 (#9378) 2022-09-07 10:34:03 +02:00
Sergio Mena
d54ed6423f Add missing changes changelog files (#9376)
* Copy over v0.34.21 section of `CHANGELOG.md`

* Missing breaking changes in `CHANGELOG_PENDING.md`

* bump

* Fix doc link

* Fix doc link 2
2022-09-06 20:48:49 +02:00
William Banfield
1067ba1571 add separated runs by UUID (#9367)
This _should_ be the last piece needed for this tool.
This allows the tool to generate reports on multiple experimental runs that may have been performed against the same chain.

The `load` tool has been updated to generate a `UUID` on startup to uniquely identify each experimental run. The `report` tool separates all of the results it reads by `UUID` and performs separate calculations for each discovered experiment.

Sample output is as follows

```
Experiment ID: 6bd7d1e8-d82c-4dbe-a1b3-40ab99e4fa30

        Connections: 1
        Rate: 1000
        Size: 1024

        Total Valid Tx: 9000
        Total Negative Latencies: 0
        Minimum Latency: 86.632837ms
        Maximum Latency: 1.151089602s
        Average Latency: 813.759361ms
        Standard Deviation: 225.189977ms

Experiment ID: 453960af-6295-4282-aed6-367fc17c0de0

        Connections: 1
        Rate: 1000
        Size: 1024

        Total Valid Tx: 9000
        Total Negative Latencies: 0
        Minimum Latency: 79.312992ms
        Maximum Latency: 1.162446243s
        Average Latency: 422.755139ms
        Standard Deviation: 241.832475ms

Total Invalid Tx: 0
```

closes: #9352 

#### PR checklist

- [ ] Tests written/updated, or no tests needed
- [ ] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [ ] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-06 14:38:08 +00:00
Julien Robert
101bf50e71 refactor: migrate to cosmos/gogoproto (#9356)
* refactor: migrate to `cosmos/gogoproto`

* add changelog

* Update Makefile

Co-authored-by: Thane Thomson <connect@thanethomson.com>

* update link

Co-authored-by: Thane Thomson <connect@thanethomson.com>
2022-09-06 07:28:37 -04:00
Thane Thomson
d7645628f1 ci: Remove "(WARNING: BETA SOFTWARE)" tagline from all upcoming releases (#9371)
This is by no means a signal that we offer any additional guarantees with our software. This warning seems somewhat pointless given that:
1. Our open source license clearly states that we offer no warranties with this software.
2. We are clearly still pre-1.0.

It also doesn't make sense to append "(WARNING: BETA SOFTWARE)" to pre-releases such as alpha releases, which are to be considered _more_ unstable than beta releases.

---

#### PR checklist

- [x] Tests written/updated, or no tests needed
- [x] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [x] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-03 14:59:29 +00:00
HaoTian
e667b855c7 fix(doc): wrong link address (#9370)
Signed-off-by: 117503445 <t117503445@gmail.com>

Signed-off-by: 117503445 <t117503445@gmail.com>
Co-authored-by: Thane Thomson <connect@thanethomson.com>
2022-09-03 08:39:13 -04:00
dependabot[bot]
c71efd1283 build(deps): Bump github.com/golangci/golangci-lint (#9323)
Bumps [github.com/golangci/golangci-lint](https://github.com/golangci/golangci-lint) from 1.48.0 to 1.49.0.
- [Release notes](https://github.com/golangci/golangci-lint/releases)
- [Changelog](https://github.com/golangci/golangci-lint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/golangci/golangci-lint/compare/v1.48.0...v1.49.0)

---
updated-dependencies:
- dependency-name: github.com/golangci/golangci-lint
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-03 08:29:35 -04:00
Thane Thomson
6bdc970377 ci: Pre-release workflows (#9366)
In preparation for the v0.37 release, this PR updates:
1. The [release guidelines](https://github.com/tendermint/tendermint/blob/thane/pre-release-workflows/RELEASES.md#pre-releases) regarding alpha and beta versions, as well as release candidates.
2. The GitHub workflows to build all 3 kinds of pre-releases for:
   1. Docker images
   2. Binaries (I'm still not 100% sure whether this is necessary, but it does act as a clear signal to users that a pre-release is available, and pre-built binaries could be useful for people running testnets who don't use Docker)
3. The Goreleaser config to auto-detect whether a tag is a pre-release and mark it as such as the release is created on GitHub.

---

#### PR checklist

- [x] Tests written/updated, or no tests needed
- [x] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [x] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-09-02 23:16:28 +00:00
William Banfield
8655080a0f test: add the loadtime report tool (#9351)
This pull request adds the report tool and modifies the loadtime libraries to better support its use.
2022-09-02 13:32:56 -04:00
Sergio Mena
bf73c7985e Update Tendermint version in main (#9360) 2022-09-02 13:01:14 -04:00
Jasmina Malicevic
6371f02810 spec: abci++ cleanup for v0.37 (#9288)
* v0.36 abci++ spec

* Basic concepts cleanup

* Resurrected beginBlock to EndBlock sequence

* Global Lock in Concurrency

* ResponseProcessProposal returns list of bytes

* Fixed broken links; added ExtendedCommitInfo and ExtendedVoteInfo

* Replace spec/abci with abci++ content

* Removed spec/abci

Co-authored-by: Sergio Mena <sergio@informal.systems>
Co-authored-by: Thane Thomson <connect@thanethomson.com>
2022-09-02 09:58:10 +02:00
Thane Thomson
b055535397 abci: Set version to 1.0.0 (#9341)
Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-09-01 21:44:45 -04:00
samricotta
2ff11e5bc2 Update rpc client header (#9276)
* Update rpc client header
2022-09-01 14:35:07 +02:00
William Banfield
70fd943bdf test: add the loadtime tool (#9342)
This pull request adds the loadtime tool. This tool leverages the tm-load-test framework. Using the framework means that the only real logic that needs to be written is the logic for Tx generation. The framework does the rest.

The tool writes a set of metadata into the transaction, including the current transaction rate, number of connections, specified size of the transaction, and the current time.
2022-08-31 16:41:15 -04:00
Thane Thomson
f1835338d9 docs: Update RELEASES.md to reflect current process (#9339)
* docs: Update RELEASES.md to reflect current process

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove unnecessary asterisk

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-08-31 07:25:42 -04:00
Thane Thomson
bdf0217bd8 ci: Prepare for v0.37 release branch (#9338)
* Add nightly E2E tests on v0.37.x branch

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add mergify config to backport to v0.37.x

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update dependabot config for v0.37.x

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-08-30 22:53:12 -04:00
Thane Thomson
cceea4de22 chore: Format and fix lints (#9336)
* make format

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Fix linting directives

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* make mockery

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Appease CI linter

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Appease CI linter

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-08-30 12:28:46 -04:00
Thane Thomson
7b40167f58 abci: Port EventAttribute field type change to main (#9335)
* types: Refactor EventAttribute (#6408)

Cherry-pick of 09a6ad7b1e

* Ensure context is honored

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Replace with tagged switch

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Ensure contexts are honored

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add UPGRADING note about type change

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove unnecessary conversion

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
2022-08-30 10:13:55 -04:00
dependabot[bot]
2313f35800 build(deps): Bump google.golang.org/grpc from 1.48.0 to 1.49.0 (#9322)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.48.0 to 1.49.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/grpc/grpc-go/releases">google.golang.org/grpc's releases</a>.</em></p>
<blockquote>
<h2>Release 1.49.0</h2>
<h1>New Features</h1>
<ul>
<li>gcp/observability: add support for Environment Variable <code>GRPC_CONFIG_OBSERVABILITY_JSON</code> (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5525">#5525</a>)</li>
<li>gcp/observability: add support for custom tags (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5565">#5565</a>)</li>
</ul>
<h1>Behavior Changes</h1>
<ul>
<li>server: reduce log level from Warning to Info for early connection establishment errors (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5524">#5524</a>)
<ul>
<li>Special Thanks: <a href="https://github.com/jpkrohling"><code>@​jpkrohling</code></a></li>
</ul>
</li>
</ul>
<h1>Bug Fixes</h1>
<ul>
<li>client: fix race in flow control that could lead to unexpected EOF errors (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5494">#5494</a>)</li>
<li>client: fix a race that could cause RPCs to time out instead of failing more quickly with UNAVAILABLE (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5503">#5503</a>)</li>
<li>client &amp; server: fix a panic caused by passing a <code>nil</code> stats handler to <code>grpc.WithStatsHandler</code> or <code>grpc.StatsHandler</code> (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5543">#5543</a>)</li>
<li>transport/server: fix a race that could cause a stray header to be sent (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5513">#5513</a>)</li>
<li>balancer: give precedence to <code>IDLE</code> over <code>TRANSIENT_FAILURE</code> when aggregating connectivity state (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5473">#5473</a>)</li>
<li>xds/xdsclient: request correct resource name when user specifies a new style resource name with empty authority (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5488">#5488</a>)</li>
<li>xds/xdsclient: NACK endpoint resources with zero weight (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5560">#5560</a>)</li>
<li>xds/xdsclient: fix bug that would reset resource version information after ADS stream restart (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5422">#5422</a>)</li>
<li>xds/xdsclient: fix goroutine leaks when load reporting is enabled (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5505">#5505</a>)</li>
<li>xds/ringhash: fix config update processing to recreate ring and picker when min/max ring size changes (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5557">#5557</a>)</li>
<li>xds/ringhash: avoid recreating subChannels when update doesn't change address weight information (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5431">#5431</a>)</li>
<li>xds/priority: fix bug which could cause priority LB to block all traffic after a config update (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5549">#5549</a>)</li>
<li>xds: fix bug when environment variable <code>GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION</code> is set to true (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5537">#5537</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="1c29e075ab"><code>1c29e07</code></a> Change version to 1.49.0 (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5583">#5583</a>)</li>
<li><a href="8e5a84e6b2"><code>8e5a84e</code></a> xds/resolver: generate channel ID randomly (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5603">#5603</a>)</li>
<li><a href="92cee3440f"><code>92cee34</code></a> gcp/observability: Add logging filters for logging, tracing, and metrics API ...</li>
<li><a href="c7fe135d12"><code>c7fe135</code></a> O11Y: Added support for custom tags (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5565">#5565</a>)</li>
<li><a href="7981af402b"><code>7981af4</code></a> test/kokoro: add missing image tagging to the xDS interop url map buildscript...</li>
<li><a href="6f34b7ad15"><code>6f34b7a</code></a> xdsclient: NACK endpoint resource if load_balancing_weight is specified and i...</li>
<li><a href="f9409d385f"><code>f9409d3</code></a> ringhash: handle config updates properly (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5557">#5557</a>)</li>
<li><a href="946dde008f"><code>946dde0</code></a> xdsclient: NACK endpoint resources with zero weight (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5560">#5560</a>)</li>
<li><a href="b89f49b0ff"><code>b89f49b</code></a> xdsclient: deflake Test/LDSWatch_PartialValid (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5552">#5552</a>)</li>
<li><a href="9bc72deba4"><code>9bc72de</code></a> grpc: remove mentions of WithBalancerName from comments (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5555">#5555</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/grpc/grpc-go/compare/v1.48.0...v1.49.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google.golang.org/grpc&package-manager=go_modules&previous-version=1.48.0&new-version=1.49.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-08-29 13:01:00 +00:00
Sergio Mena
3233568cee Added PrepareProposal and ProcessProposal data CHANGELOG_PENDING.md. Reworked UPGRADING.md (#9315)
* master-->main in `CONTRIBUTING.md`

* Added feature branches in `CONTRIBUTING.md`

* Fixes to `UPGRADING.md`

* [cherrypicked] docs: minor tweaks (#5404)

* docs: fix /validators description

Refs https://github.com/tendermint/spec/pull/169

* consensus: remove nil err from logging statement

* update UPGRADING.md

* note about LightBlocks

* Reworked "Unreleased" section of `UPGRADING.md`

* Added PrepareProposal and ProcessProposal to `CHANGELOG_PENDING.md`

* Apply suggestions from @thanethomson's code review

Co-authored-by: Thane Thomson <connect@thanethomson.com>

* Addressed @tychoish's comment

Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
Co-authored-by: Thane Thomson <connect@thanethomson.com>
2022-08-26 23:53:13 +02:00
Thane Thomson
9f76e8da15 Temporarily revert #9175: remove lastresulthash from merklization in lastresult hash (#9313)
* Revert "remove lastresulthash from merklization in lastresult hash (#9175)"

This reverts commit bff63aec83.

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Clarify wording in ABCI upgrade guidelines

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-08-24 14:34:36 -04:00
Thane Thomson
28cfb039c9 docs: Add redirects to GitHub for spec links (#9311)
* Add spec redirects

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Use hack to make redirects work

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-08-24 10:14:54 -04:00
Callum Waters
5f932a53f0 e23: fix generation by considering evidence age in retain height (#9306) 2022-08-23 11:28:32 +02:00
Sergio Mena
50b5c23d88 Merge branch 'feature/abci++ppp' 2022-08-22 17:16:17 +02:00
Callum Waters
b37f062619 e2e: add evidence tests (#9292) 2022-08-22 13:33:47 +02:00
samricotta
aa303edaef Forward port discard abci responses change (#9286)
* Backport of sam/abci-responses (#9090) (#9159)

Signed-off-by: Thane Thomson <connect@thanethomson.com>
Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>
Co-authored-by: Thane Thomson <connect@thanethomson.com>
2022-08-22 12:53:01 +02:00
Callum Waters
2d8df1bd4e proto: deduplicate consensus params (#9287) 2022-08-22 10:50:21 +02:00
Thane Thomson
d886bc8fdd docs: Capture UX-oriented practices for changelog (#9284) 2022-08-20 10:02:39 -04:00
Thane Thomson
daaf5d6441 docs: Update all docs to prepare for v0.37 (#9243)
* Update docs references from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update DOCS_README to reflect current reality

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update vuepress config with current versions and updated discussions link

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update generated docs versions

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update docs build to use temp folder instead of home

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Document build-docs Makefile target

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add serve-docs Makefile target to serve local build of docs

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Ensure 404 page is copied during docs build

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Redirect /master/ to /main/

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Attempt to resolve #7908

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update OpenAPI references from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update CHANGELOG references from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update Docker readme references from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update UPGRADING references from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update package-specific documentation references from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update spec references from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update all code comment references to docs site from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Build v0.34.x as "latest"

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Explicitly mark v0.34 docs as latest in version selector

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update all links from docs.tendermint.com/main to docs.tendermint.com/latest

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ci: Redeploy docs on pushes to v0.34.x

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Temporarily copy spec directory into docs while building

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add nav link to main and clearly mark as unstable

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Revert to only publishing docs in nav for v0.34 and v0.33 with no latest

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Link to docs.tendermint.com/v0.34 from RFCs

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Rather just use main for all docs.tendermint.com references on main branch

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Rename GitHub tree links from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update link for ABCI Rust client

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update github links from master to main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update badges in root readme

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove codecov badge since we do not use it any more

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove Java and Kotlin tutorials

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove specs from docs build

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Migrate spec links to GitHub repo from docs site

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove references to non-existent PEX reactor spec

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Fix linting badge in README

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-08-19 13:18:33 -04:00
Thane Thomson
3cc976482d docs: Apply standard Apache 2.0 license (#9293)
Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-08-19 11:36:29 -04:00
Callum Waters
0ca3a89c90 e2e: add abci delays (#9254) 2022-08-19 12:00:58 +02:00
William Banfield
1a4d9397e9 abci++: update PrepareProposal API to accept just a list of bytes (#9283)
This changes the ResponsePrepareProposal type, substituting the []TxRecord for just []bytes. This change is made in the .proto file and in all necessary additional places in the code.
2022-08-18 16:33:19 -04:00
fatcat22
c8302c5fcb consensus: fix round number when handling RoundStepNewRound timeout (#9252) 2022-08-18 10:24:06 +02:00
Sergio Mena
fb9afcc969 Restore e2e nightly workflow on feature/abci++ppp branch (#9280) 2022-08-17 21:05:53 +02:00
Sergio Mena
622b930e3a abci-cli: PrepareProposal and ProcessProposal (#9281)
* [cherrypicked] abci-cli: added `PrepareProposal` command to cli (#8656)

* Prepare prosal cli

* [cherrypicked + fixes] abci-cli: Add `process_proposal` command to abci-cli (#8901)

* Add `process_proposal` command to abci-cli

* Added process proposal to the 'tutorial' examples

* Added entry in CHANGELOG_PENDING.md

* Allow empty blocks in PrepareProposal, ProcessProposal, and FinalizeBlock

* Fix minimum arguments

* Add tests for empty block

* Updated abci-cli doc

Co-authored-by: Sergio Mena <sergio@informal.systems>
Co-authored-by: Jasmina Malicevic <jasmina.dustinac@gmail.com>

* Addressed @williambanfield's comment

Co-authored-by: Jasmina Malicevic <jasmina.dustinac@gmail.com>
Co-authored-by: Hernán Vanzetto <hernan.vanzetto@gmail.com>
2022-08-17 20:47:52 +02:00
William Banfield
1069ffc6aa config: backport the rename of fastsync to blocksync (#9259)
This is largely a cherry pick of #6755 with some additional fixups added where detected. 
This change moves the blockchain package to a package called blocksync. Additionally, it renames the relevant uses of the term `fastsync` to `blocksync`.

closes: #9227 

#### PR checklist

- [ ] Tests written/updated, or no tests needed
- [x] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [x] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-08-17 15:19:20 +00:00
William Banfield
7bd86ec004 consensus: backport abci and consensus metrics (#9273)
Partial backport of #8480
2022-08-17 09:37:45 -04:00
samricotta
9993514893 abci: Remove SetOption #5447 #9091 (#9266)
* Remove set option for abci
2022-08-16 22:58:04 +02:00
Igor Konnov
3003e05581 Update type annotations in the TLA+ spec of Tendermint for accountability (#9263)
* update Apalache type annotations and split evidence into 3 variables

* remove the duplicate of AllPrevotes, due to merge
2022-08-16 16:12:04 +02:00
AdamKorcz
498657f128 test/fuzz: fix OSS-Fuzz build (#9183) 2022-08-16 15:59:24 +02:00
William Banfield
c322b89b2a RFC-024: block structure consolidation (#8457)
This RFC lays out a proposed set of changes for consolidating the set of information that may be included in the block structure.

{{ [rendered](https://github.com/tendermint/tendermint/blob/wb/rfc-block-structure/docs/rfc/rfc-020-block-structure-consolidation.md) }}
2022-08-16 13:51:55 +00:00
Thane Thomson
cbc7a1abcf spec: Sync Light Client TLA+ code with master (#9238)
* Typo fix in README.md (#350)

* Updated Apalache type annotations (#395)

Co-authored-by: Prajjwol Gautam <prajjwol@gmail.com>
Co-authored-by: Kukovec <jure.kukovec@gmail.com>
2022-08-12 14:33:47 -04:00
Sergio Mena
670abbc330 Merge pull request #9236 from tendermint/sergio/merging-main-abci++ppp
Merge `main` into `feature/abci++ppp`
2022-08-12 15:55:47 +02:00
Sergio Mena
7dc4f934b0 Merge branch main into feature/abci++ppp 2022-08-12 13:59:19 +02:00
Sergio Mena
cb570f6672 ABCI types.proto. Handle remaining discrepancies (#9224)
* [cherrypicked] version: add abci version to handshake (#5706)

- add `AbciVersion` RequestInfo

Closes: #2804

* make proto-gen

* Bump ABCI version: Prepare and Process proposal

Co-authored-by: Marko <marbar3778@yahoo.com>
2022-08-12 11:57:13 +02:00
Marko
f36999e484 retract all of 0.35 (#9198) 2022-08-12 11:47:36 +02:00
Thane Thomson
ae1fc74f80 abci: Make ABCI and P2P wire-level length delimiters consistent (#9182)
* abci: use protoio for length delimitation (#5818)

Migrate ABCI to use protoio (uint64 length delimiters) instead of int64
length delimiters to be consistent with the approach used in the P2P
layer.

Closes: #5783

* Import ReadMsg interface change from #5868

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Convert PR number to link in UPGRADING

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update Tendermint Socket Protocol docs to reflect length prefix encoding change

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Clarify that length delimiters are varints

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Signed-off-by: Thane Thomson <connect@thanethomson.com>
Co-authored-by: Marko <marbar3778@yahoo.com>
2022-08-11 13:30:39 -04:00
Sergio Mena
c4eb6113a8 Remove unused code in internal directory (#9223) 2022-08-11 17:33:55 +02:00
Sergio Mena
25b0c7c78e PrepareProposal/ProcessProposal: Dealing with block data exposed to App (#9219)
* [cherrypicked] abci++: only include meaningful header fields in data passed-through to application (#8216)

* make proto-gen

* Fix kvstore tests

* Small changes to abci protobufs taken from v0.36.x

* make proto-gen (again)

* [Partial cherrypick] Restore `Commit` to the ABCI++ spec, and other late modifications (backport #8796) (#8936)

* Restore `Commit` to the ABCI++ spec, and other late modifications (#8796)

* Added VoteExtensionsEnableHeight

* Fix reference to `modified`

* Removed old pseudo-code, now included in spec

* Removed markdown warnings in abci++_basic_concepts_002_draft.md

* Restored `Commit` in the Methods section

* Addressed remaining markdown warnings

* Revisited intro and basic concepts section

* Extra pass at all spec sections to recover Commit, and other ABCI++ spec modifications

* Fixed links

* make proto-gen

* Remove _primes_ from spec notation

* Update proto/tendermint/abci/types.proto

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

* Update spec/abci++/abci++_tmint_expected_behavior_002_draft.md

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

* Addressed @cmwaters' comments

* Addressed @angbrav's and @mpoke's comments on spec

* make proto-gen

* Fix MD anchor reference

* Clarify throughout the spec when `ProcessProposal` and `VerifyVoteExtension` are called

* Update spec/abci++/abci++_app_requirements_002_draft.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci++/abci++_app_requirements_002_draft.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci++/abci++_app_requirements_002_draft.md

Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>

* Update spec/abci++/abci++_basic_concepts_002_draft.md

Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>

* Update spec/abci++/abci++_basic_concepts_002_draft.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci++/abci++_basic_concepts_002_draft.md

Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>

* Update spec/abci++/abci++_methods_002_draft.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci++/abci++_tmint_expected_behavior_002_draft.md

Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>

* Addresed comments

* Renamed 'draft' files

* Adatped links to new filenames

* Fixed links and minor cosmetic changes

* Renamed 'byzantine_validators' to 'misbehavior' in ABCI++ spec and protobufs

* make proto-gen

* Renamed 'byzantine_validators' to 'misbehavior' in the code

* Fixed link

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_basic_concepts.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Update spec/abci++/abci++_methods.md

Co-authored-by: Daniel <daniel.cason@usi.ch>

* Addressed @cason's comments

* Clarified conditions for `ProcessProposal` call at proposer

Co-authored-by: Callum Waters <cmwaters19@gmail.com>
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>
Co-authored-by: Daniel <daniel.cason@usi.ch>
(cherry picked from commit 331860c2a8)

* Fixed merge conflicts

Co-authored-by: Sergio Mena <sergio@informal.systems>

* make proto-gen (and again)

* make build

* fix UTs

Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-08-11 11:21:43 +02:00
Jacob Gadikian
a6dde14ec4 do not use ioutil (#9206) 2022-08-10 14:35:14 -04:00
Sam Kleinman
152a2fa5c9 metrics: add metricsgen makefile target (#9172)
Follow on work as a missing piece of #9156, to make it possible to
generate metrics automatically using existing build infrastructure.
2022-08-09 21:00:55 +00:00
dependabot[bot]
f295b4d431 build(deps): Bump github.com/golangci/golangci-lint from 1.42.1 to 1.48.0 (#9203)
Bumps [github.com/golangci/golangci-lint](https://github.com/golangci/golangci-lint) from 1.42.1 to 1.48.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/golangci/golangci-lint/releases">github.com/golangci/golangci-lint's releases</a>.</em></p>
<blockquote>
<h2>v1.48.0</h2>
<h2>Changelog</h2>
<ul>
<li>368c41cd build(deps): bump github.com/daixiang0/gci from 0.5.0 to 0.6.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3035">#3035</a>)</li>
<li>2d8fea81 build(deps): bump github.com/daixiang0/gci from 0.6.0 to 0.6.2 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3058">#3058</a>)</li>
<li>aeb5860c build(deps): bump github.com/kisielk/errcheck from 1.6.1 to 1.6.2 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3059">#3059</a>)</li>
<li>0559b922 build(deps): bump revgrep to HEAD (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3054">#3054</a>)</li>
<li>6313fa9a contextcheck: disable linter (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3050">#3050</a>)</li>
<li>0ba1388a feat: add usestdlibvars (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3016">#3016</a>)</li>
<li>1557692e feat: go1.19 support  (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3037">#3037</a>)</li>
<li>15cba447 gci: add missing <code>custom-order</code> setting (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3052">#3052</a>)</li>
<li>9a1b9492 ifshort: deprecate linter (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3034">#3034</a>)</li>
<li>f8f8f9a6 nolint: drop allow-leading-space option and add &quot;nolint:all&quot; (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3002">#3002</a>)</li>
</ul>
<h2>v1.47.3</h2>
<h2>Changelog</h2>
<ul>
<li>72fc41ce build(deps): bump github.com/BurntSushi/toml from 1.1.0 to 1.2.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3009">#3009</a>)</li>
<li>57d61afb build(deps): bump github.com/GaijinEntertainment/go-exhaustruct/v2 from 2.2.0 to 2.2.2 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3030">#3030</a>)</li>
<li>9cb17e4f build(deps): bump github.com/alingse/asasalint from 0.0.10 to 0.0.11 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3003">#3003</a>)</li>
<li>2ab46788 build(deps): bump github.com/daixiang0/gci from 0.4.3 to 0.5.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3031">#3031</a>)</li>
<li>03d9b113 build(deps): bump github.com/ryancurrah/gomodguard from 1.2.3 to 1.2.4 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3029">#3029</a>)</li>
<li>e55f22c7 build(deps): bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3010">#3010</a>)</li>
<li>c7ed8b67 build(deps): bump github.com/sivchari/nosnakecase from 1.5.0 to 1.7.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3008">#3008</a>)</li>
<li>95d57d99 build(deps): bump gitlab.com/bosi/decorder from 0.2.2 to 0.2.3 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3033">#3033</a>)</li>
<li>d186efe9 build(deps): bump honnef.co/go/tools from 0.3.2 to 0.3.3 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3032">#3032</a>)</li>
<li>846fab81 cgo: fix linters ignoring Cgo files (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3025">#3025</a>)</li>
<li>d44cd49a feat: remove some go1.18 limitations (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3001">#3001</a>)</li>
<li>886fbd71 gci: fix panic with invalid configuration option (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3019">#3019</a>)</li>
</ul>
<h2>v1.47.2</h2>
<h2>Changelog</h2>
<ul>
<li>61673b34 revive: ignore slow rules (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2999">#2999</a>)</li>
</ul>
<h2>v1.47.1</h2>
<h2>Changelog</h2>
<ul>
<li>a91463cd build(deps): bump github.com/daixiang0/gci from 0.4.2 to 0.4.3 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2992">#2992</a>)</li>
<li>4c8bdc70 build(deps): bump github.com/sivchari/tenv from 1.6.0 to 1.7.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2988">#2988</a>)</li>
<li>4e60e8a8 gci: fix options display (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2989">#2989</a>)</li>
<li>fd87bd1e gci: remove the use of stdin (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2984">#2984</a>)</li>
</ul>
<h2>v1.47.0</h2>
<h2>Changelog</h2>
<ul>
<li>b4154027 Add linter <code>asasalint</code> to lint pass []any as any (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2968">#2968</a>)</li>
<li>1d8a15a0 add nosnakecase lint (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2828">#2828</a>)</li>
<li>2a1edcef build(deps): bump github.com/Antonboom/errname from 0.1.6 to 0.1.7 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2888">#2888</a>)</li>
<li>c766184c build(deps): bump github.com/GaijinEntertainment/go-exhaustruct/v2 from 2.1.0 to 2.2.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2916">#2916</a>)</li>
<li>b8f1e2a5 build(deps): bump github.com/daixiang0/gci from 0.3.4 to 0.4.0 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2965">#2965</a>)</li>
<li>5e183652 build(deps): bump github.com/daixiang0/gci from 0.4.0 to 0.4.1 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2973">#2973</a>)</li>
<li>e60937a1 build(deps): bump github.com/daixiang0/gci from 0.4.1 to 0.4.2 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/2979">#2979</a>)</li>
</ul>

</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/golangci/golangci-lint/blob/master/CHANGELOG.md">github.com/golangci/golangci-lint's changelog</a>.</em></p>
<blockquote>
<h3>v1.48.0</h3>
<ol>
<li>new linters
<ul>
<li><code>usestdlibvars</code>:<a href="https://github.com/sashamelentyev/usestdlibvars">https://github.com/sashamelentyev/usestdlibvars</a></li>
</ul>
</li>
<li>updated linters
<ul>
<li><code>contextcheck</code>: disable linter</li>
<li><code>errcheck</code>: from 1.6.1 to 1.6.2</li>
<li><code>gci</code>: add missing <code>custom-order</code> setting</li>
<li><code>gci</code>: from 0.5.0 to 0.6.0</li>
<li><code>ifshort</code>: deprecate linter</li>
<li><code>nolint</code>: drop allow-leading-space option and add &quot;nolint:all&quot;</li>
<li><code>revgrep</code>: bump to HEAD</li>
</ul>
</li>
<li>documentation
<ul>
<li>remove outdated info on source install</li>
</ul>
</li>
<li>misc
<ul>
<li>go1.19 support</li>
</ul>
</li>
</ol>
<h3>v1.47.3</h3>
<ol>
<li>updated linters:
<ul>
<li>remove some go1.18 limitations</li>
<li><code>asasalint</code>: from 0.0.10 to 0.0.11</li>
<li><code>decorder</code>: from 0.2.2 to v0.2.3</li>
<li><code>gci</code>: fix panic with invalid configuration option</li>
<li><code>gci</code>: from 0.4.3 to v0.5.0</li>
<li><code>go-exhaustruct</code>: from 2.2.0 to 2.2.2</li>
<li><code>gomodguard</code>: from 1.2.3 to 1.2.4</li>
<li><code>nosnakecase</code>: from 1.5.0 to 1.7.0</li>
<li><code>honnef.co/go/tools</code>: from 0.3.2 to v0.3.3</li>
</ul>
</li>
<li>misc
<ul>
<li>cgo: fix linters ignoring CGo files</li>
</ul>
</li>
</ol>
<h3>v1.47.2</h3>
<ol>
<li>updated linters:
<ul>
<li><code>revive</code>: ignore slow rules</li>
</ul>
</li>
</ol>
<h3>v1.47.1</h3>
<ol>
<li>updated linters:
<ul>
<li><code>gci</code>: from 0.4.2 to 0.4.3</li>
<li><code>gci</code>: remove the use of stdin</li>
<li><code>gci</code>: fix options display</li>
<li><code>tenv</code>: from 1.6.0 to 1.7.0</li>
<li><code>unparam</code>: bump to HEAD</li>
</ul>
</li>
</ol>
<h3>v1.47.0</h3>
<ol>
<li>new linters:
<ul>
<li><code>asasalint</code>: <a href="https://github.com/alingse/asasalint">https://github.com/alingse/asasalint</a></li>
</ul>
</li>
</ol>

</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="2d8fea819e"><code>2d8fea8</code></a> build(deps): bump github.com/daixiang0/gci from 0.6.0 to 0.6.2 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3058">#3058</a>)</li>
<li><a href="aeb5860ca8"><code>aeb5860</code></a> build(deps): bump github.com/kisielk/errcheck from 1.6.1 to 1.6.2 (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3059">#3059</a>)</li>
<li><a href="0559b9220b"><code>0559b92</code></a> build(deps): bump revgrep to HEAD (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3054">#3054</a>)</li>
<li><a href="3ffde13a17"><code>3ffde13</code></a> dev: remove stable from actions/setup-go (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3055">#3055</a>)</li>
<li><a href="1557692e59"><code>1557692</code></a> feat: go1.19 support  (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3037">#3037</a>)</li>
<li><a href="6313fa9a67"><code>6313fa9</code></a> contextcheck: disable linter (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3050">#3050</a>)</li>
<li><a href="0ba1388a41"><code>0ba1388</code></a> feat: add usestdlibvars (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3016">#3016</a>)</li>
<li><a href="15cba447fd"><code>15cba44</code></a> gci: add missing <code>custom-order</code> setting (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3052">#3052</a>)</li>
<li><a href="452544a2e7"><code>452544a</code></a> build(deps): bump gatsby from 4.15.2 to 4.19.2 in /docs (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3046">#3046</a>)</li>
<li><a href="f9dfb687aa"><code>f9dfb68</code></a> build(deps): bump gatsby-transformer-yaml from 4.13.0 to 4.19.0 in /docs (<a href="https://github-redirect.dependabot.com/golangci/golangci-lint/issues/3045">#3045</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/golangci/golangci-lint/compare/v1.42.1...v1.48.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/golangci/golangci-lint&package-manager=go_modules&previous-version=1.42.1&new-version=1.48.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-08-09 15:21:16 +00:00
William Banfield
0bea0647fe tools: remove mockery from tools.go (#9196)
The `mockery` project recommends against using a binary of `mockery` that has been created using `go install`. https://github.com/vektra/mockery/pull/456. Developers of Tendermint wishing to generate mocks should avoid having a version of `mockery` on their path that does not match the version listed in  [mockery_generate.sh](10e1ac8fea/scripts/mockery_generate.sh (L11)). To make this easier for developers, the `mockery_generate.sh` script uses a containerized copy of `mockery` if `mockery` is not present on the developer's `PATH`. This containerized version of `mockery` uses the same version of mockery as our CI pipelines and allows all developers to automatically use the same version without having to manage it themselves. 

#### PR checklist

- [ ] Tests written/updated, or no tests needed
- [ ] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [ ] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed
2022-08-09 15:12:31 +00:00
Callum Waters
f861062ee2 abci: implement process proposal to spec (#9122) 2022-08-09 15:15:18 +02:00
Sam Kleinman
d5ec276052 e2e: fix out of sync configuration (#9199)
The v0.34.x tests have been failing (or reporting failures, I don't
believe that this is a real failure,) because the CI configuration has
been out of sync with itself, likely due to a mistake during
backporting configs from the `master` branch.

The entire 0.34.x e2e test suite takes 26 minutes to run, plus about 7
minutes to build the docker image. Each split has to build the same
docker image, (and is therefore a cap on the amount of parallelism we
can get at the moment.) Having more groups, just seems like we'll be
burning money building the docker image with no really meaningful
difference in throughput. For a nightly test that people don't really
wait on, the current latency (time-to-completion) of roughly 19
minutes, isn't causing in friction.
2022-08-09 12:02:14 +00:00
Marko
bff63aec83 remove lastresulthash from merklization in lastresult hash (#9175)
remove gas from merklization in headers


Im not sure where to change docs since main points to the spec repo but that repo is archived. Maybe someone can help me?
2022-08-09 08:16:41 +00:00
William Banfield
69845bb44e metrics: fixup after cherry-pick (#9195)
* fixup after cherry-pick

* cherry-pick fixups
2022-08-08 15:55:01 -04:00
William Banfield
10e1ac8fea metrics: transition all metrics to using metricsgen generated constructors. (port of #8488) (#9178)
This pull request completes the change to the `metricsgen` metrics. It adds `go generate` directives to all of the files containing the `Metrics` structs.

Using the outputs of `metricsdiff` between these generated metrics and `main`, we can see that there is a minimal diff between the two sets of metrics when run locally. The diff here stems from removal of the word 'message' which was done in v0.36+ and is ultimately a better phrasing. This metric has not yet been released, so this phrasing is preferred.

```
./metricsdiff old new
Metric changes:
+++ tendermint_consensus_full_prevote_delay
+++ tendermint_consensus_quorum_prevote_delay
--- tendermint_consensus_full_prevote_message_delay
--- tendermint_consensus_quorum_prevote_message_delay
```

This change also adds parsing for a `metrics:` key in a field comment. If a comment line begins with `//metrics:` the rest of the line is interpreted to be the metric help text. Additionally, a bug where lists of labels were not properly quoted in the `metricsgen` rendered output was fixed.

In my view, docs and tests are not needed for this internal only change.

---
#### PR checklist

- [ ] Tests written/updated, or no tests needed
- [ ] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [ ] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed

Ports #8488 to main
2022-08-08 16:53:00 +00:00
dependabot[bot]
74dd21eb89 build(deps): Bump docker/build-push-action from 3.1.0 to 3.1.1 (#9189)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3.1.0 to 3.1.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/docker/build-push-action/releases">docker/build-push-action's releases</a>.</em></p>
<blockquote>
<h2>v3.1.1</h2>
<ul>
<li>Fix GitHub token not passed with Git context if subdir defined by <a href="https://github.com/crazy-max"><code>@​crazy-max</code></a> (<a href="https://github-redirect.dependabot.com/docker/build-push-action/issues/663">#663</a>)</li>
<li>Replace deprecated <code>fs.rmdir</code> with <code>fs.rm</code> by <a href="https://github.com/bendrucker"><code>@​bendrucker</code></a> (<a href="https://github-redirect.dependabot.com/docker/build-push-action/issues/657">#657</a>)</li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/docker/build-push-action/compare/v3.1.0...v3.1.1">https://github.com/docker/build-push-action/compare/v3.1.0...v3.1.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="c84f382811"><code>c84f382</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/docker/build-push-action/issues/663">#663</a> from crazy-max/fix-git-token-cond</li>
<li><a href="cd5d0b79ea"><code>cd5d0b7</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/docker/build-push-action/issues/661">#661</a> from dud225/subdir_context</li>
<li><a href="30a32246ba"><code>30a3224</code></a> Fix GitHub token not passed with Git context if subdir defined</li>
<li><a href="1f19633b92"><code>1f19633</code></a> Update comment regarding the support of subdir context</li>
<li><a href="67af6dc1d3"><code>67af6dc</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/docker/build-push-action/issues/657">#657</a> from bendrucker/deprecated-fs-rmdir</li>
<li><a href="988cb093f2"><code>988cb09</code></a> replace deprecated <code>fs.rmdir</code> with <code>fs.rm</code></li>
<li>See full diff in <a href="https://github.com/docker/build-push-action/compare/v3.1.0...v3.1.1">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/build-push-action&package-manager=github_actions&previous-version=3.1.0&new-version=3.1.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-08-08 13:35:59 +00:00
dependabot[bot]
ad1f9b49bc build(deps): Bump github.com/prometheus/client_golang (#9190)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.12.2 to 1.13.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.12.2...v1.13.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-08 09:34:21 -04:00
Thane Thomson
ef4e37b532 ci: Restore ToC check for ADRs/RFCs (#9180)
* Import presubmit TOC check script from master and fix warning

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Fix misspelled ADR link discovered by presubmit script

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Restore docs-toc workflow

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Create makefile target for docs ToC check

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Use makefile target in CI workflow for docs ToC check

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-08-06 13:19:05 -04:00
Thane Thomson
03c79b666d ci: Fix nightly E2E notifications (#9179)
Update the nightly E2E workflows to fix the notifications for the
v0.34.x branch while also simplifying the messages and making them more
readable.

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-08-06 10:17:21 -04:00
Thane Thomson
1148759a94 ci: Update nightly E2E notifications (#9177) 2022-08-05 21:38:14 -04:00
William Banfield
608933b73e consensus: additional timing metrics (port of #7849) (#9168)
This change introduces an additional set of metrics aimed at helping operators understand the timing for consensus.

This change adds the following metrics:

```
tendermint_consensus_round_duration_seconds_bucket{chain_id="test-chain-IrF74Y",le="0.1"} 29
tendermint_consensus_round_duration_seconds_bucket{chain_id="test-chain-IrF74Y",le="0.2682695795279726"} 29
tendermint_consensus_round_duration_seconds_bucket{chain_id="test-chain-IrF74Y",le="0.7196856730011522"} 29
tendermint_consensus_round_duration_seconds_bucket{chain_id="test-chain-IrF74Y",le="1.9306977288832508"} 29
tendermint_consensus_round_duration_seconds_bucket{chain_id="test-chain-IrF74Y",le="5.1794746792312125"} 29
tendermint_consensus_round_duration_seconds_bucket{chain_id="test-chain-IrF74Y",le="13.894954943731381"} 29
tendermint_consensus_round_duration_seconds_bucket{chain_id="test-chain-IrF74Y",le="37.27593720314942"} 29
tendermint_consensus_round_duration_seconds_bucket{chain_id="test-chain-IrF74Y",le="100.00000000000006"} 29
tendermint_consensus_round_duration_seconds_bucket{chain_id="test-chain-IrF74Y",le="+Inf"} 29
tendermint_consensus_round_duration_seconds_sum{chain_id="test-chain-IrF74Y"} 0.028651869999999996
tendermint_consensus_round_duration_seconds_count{chain_id="test-chain-IrF74Y"} 29
```

```
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Commit",le="0.1"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Commit",le="0.2682695795279726"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Commit",le="0.7196856730011522"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Commit",le="1.9306977288832508"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Commit",le="5.1794746792312125"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Commit",le="13.894954943731381"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Commit",le="37.27593720314942"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Commit",le="100.00000000000006"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Commit",le="+Inf"} 29
tendermint_consensus_step_duration_seconds_sum{chain_id="test-chain-IrF74Y",step="Commit"} 0.26650875
tendermint_consensus_step_duration_seconds_count{chain_id="test-chain-IrF74Y",step="Commit"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewHeight",le="0.1"} 0
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewHeight",le="0.2682695795279726"} 0
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewHeight",le="0.7196856730011522"} 0
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewHeight",le="1.9306977288832508"} 28
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewHeight",le="5.1794746792312125"} 28
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewHeight",le="13.894954943731381"} 28
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewHeight",le="37.27593720314942"} 28
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewHeight",le="100.00000000000006"} 28
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewHeight",le="+Inf"} 28
tendermint_consensus_step_duration_seconds_sum{chain_id="test-chain-IrF74Y",step="NewHeight"} 27.773921702
tendermint_consensus_step_duration_seconds_count{chain_id="test-chain-IrF74Y",step="NewHeight"} 28
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewRound",le="0.1"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewRound",le="0.2682695795279726"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewRound",le="0.7196856730011522"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewRound",le="1.9306977288832508"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewRound",le="5.1794746792312125"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewRound",le="13.894954943731381"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewRound",le="37.27593720314942"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewRound",le="100.00000000000006"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="NewRound",le="+Inf"} 29
tendermint_consensus_step_duration_seconds_sum{chain_id="test-chain-IrF74Y",step="NewRound"} 0.168961052
tendermint_consensus_step_duration_seconds_count{chain_id="test-chain-IrF74Y",step="NewRound"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Precommit",le="0.1"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Precommit",le="0.2682695795279726"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Precommit",le="0.7196856730011522"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Precommit",le="1.9306977288832508"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Precommit",le="5.1794746792312125"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Precommit",le="13.894954943731381"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Precommit",le="37.27593720314942"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Precommit",le="100.00000000000006"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Precommit",le="+Inf"} 29
tendermint_consensus_step_duration_seconds_sum{chain_id="test-chain-IrF74Y",step="Precommit"} 0.06414115999999999
tendermint_consensus_step_duration_seconds_count{chain_id="test-chain-IrF74Y",step="Precommit"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Prevote",le="0.1"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Prevote",le="0.2682695795279726"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Prevote",le="0.7196856730011522"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Prevote",le="1.9306977288832508"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Prevote",le="5.1794746792312125"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Prevote",le="13.894954943731381"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Prevote",le="37.27593720314942"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Prevote",le="100.00000000000006"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Prevote",le="+Inf"} 29
tendermint_consensus_step_duration_seconds_sum{chain_id="test-chain-IrF74Y",step="Prevote"} 0.177714525
tendermint_consensus_step_duration_seconds_count{chain_id="test-chain-IrF74Y",step="Prevote"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Propose",le="0.1"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Propose",le="0.2682695795279726"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Propose",le="0.7196856730011522"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Propose",le="1.9306977288832508"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Propose",le="5.1794746792312125"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Propose",le="13.894954943731381"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Propose",le="37.27593720314942"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Propose",le="100.00000000000006"} 29
tendermint_consensus_step_duration_seconds_bucket{chain_id="test-chain-IrF74Y",step="Propose",le="+Inf"} 29
tendermint_consensus_step_duration_seconds_sum{chain_id="test-chain-IrF74Y",step="Propose"} 0.221851927
tendermint_consensus_step_duration_seconds_count{chain_id="test-chain-IrF74Y",step="Propose"} 29
```


```
tendermint_consensus_block_gossip_parts_received{chain_id="test-chain-IrF74Y",matches_current="true"} 29
```


---

#### PR checklist

- [x] Tests written/updated, or no tests needed
- [ ] `CHANGELOG_PENDING.md` updated, or no changelog entry needed
- [x] Updated relevant documentation (`docs/`) and code comments, or no
      documentation updates needed

Closes: #9166
2022-08-05 21:24:02 +00:00
William Banfield
b92a19b2ce proxy: add initial set of abci metrics (port of #7115) (#9169)
* internal/proxy: add initial set of abci metrics (#7115)

This PR adds an initial set of metrics for use ABCI. The initial metrics enable the calculation of timing histograms and call counts for each of the ABCI methods. The metrics are also labeled as either 'sync' or 'async' to determine if the method call was performed using ABCI's `*Async` methods.

An example of these metrics is included here for reference:
```
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="0.0001"} 0
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="0.0004"} 5
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="0.002"} 12
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="0.009"} 13
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="0.02"} 13
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="0.1"} 13
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="0.65"} 13
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="2"} 13
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="6"} 13
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="25"} 13
tendermint_abci_connection_method_timing_bucket{chain_id="ci",method="commit",type="sync",le="+Inf"} 13
tendermint_abci_connection_method_timing_sum{chain_id="ci",method="commit",type="sync"} 0.007802058000000001
tendermint_abci_connection_method_timing_count{chain_id="ci",method="commit",type="sync"} 13
```

These metrics can easily be graphed using prometheus's `histogram_quantile(...)` method to pick out a particular quantile to graph or examine. I chose buckets that were somewhat of an estimate of expected range of times for ABCI operations. They start at .0001 seconds and range to 25 seconds. The hope is that this range captures enough possible times to be useful for us and operators.

* fixup

* fixups

* docs: add abci timing metrics to the metrics docs (#7311)

* format table
2022-08-05 13:29:00 -04:00
William Banfield
6b499aeb31 DOCKER: use go 1.18 (#9170) 2022-08-04 17:57:53 -04:00
Sergio Marin
88186f76fc (docker) enable cross platform build using docker buildx (\#9073) (#9074) 2022-08-04 10:01:37 +02:00
Sam Kleinman
4f30c90e62 metricsgen: port metrics code generation tool (#9156)
This is a port of #8470 and #8501 from the former mainline branch, in
support of #2600 and #9076. 

No additional changes other than checking out the code have been
implemented in this PR. A subsequent PR will incorporate this code.
2022-08-03 14:02:18 +00:00
Callum Waters
ea271c534a abci: remove counter app (port #6684) (#9143) 2022-08-03 13:44:34 +02:00
Callum Waters
4206a0e9b7 remove v1 and v2 blocksync protocol impementations (#9146) 2022-08-02 11:30:28 +02:00
Arnaud Mimart
eb762cf5d7 cli: set node p2p external address with cmd flag (#9107)
Closes #9035

Add the `p2p.external-address` command line argument to configure the node external address.
2022-08-01 17:26:08 +00:00
Mark Rushakoff
b6a515a818 docs/rfc: add testnet RFC (#9124)
* docs/rfc: add testnet RFC

Following several discussions internal to the Tendermint engineering
team, I am posting an RFC discussing the high-level details of the
Tendermint team owning and operating a long-lived testnet in order to
build experience running Tendermint, and to demonstrate that Tendermint
is stable under production workloads.

The outcome of this RFC will be a new track of work to begin building
and maintaining a testnet associated with the main branch of tendermint.
See the "Testnet MVP" section specifically for some of the first
milestones.

Note, I added the RFC where it would live once #9115 is merged to
restore the RFC layout from the v0.36.x branch. docs/rfc/README.md will
need to be updated to include this RFC once #9115 is merged.

This RFC is related to #9078.

* docs/rfc: minor updates to testnet rfc

* docs/rfc: respond to more feedback on testnet RFC

* docs/rfc: add RFC 023 to rfc index
2022-08-01 11:33:04 -04:00
Callum Waters
07d242c461 e2e: remove maverick (#9148) 2022-08-01 17:15:03 +02:00
Callum Waters
1e9d81fb8a chore: bump go to 1.18 (#9147) 2022-08-01 16:45:25 +02:00
dependabot[bot]
5305fa79cf build(deps): Bump github.com/bufbuild/buf from 1.4.0 to 1.7.0 (#9138)
Bumps [github.com/bufbuild/buf](https://github.com/bufbuild/buf) from 1.4.0 to 1.7.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/bufbuild/buf/releases">github.com/bufbuild/buf's releases</a>.</em></p>
<blockquote>
<h2>v1.7.0</h2>
<ul>
<li>Support protocol and encoding client options based on content-type in Studio Agent.</li>
<li>Add <code>--draft</code> flag to <code>buf push</code>.</li>
<li>Add <code>buf beta registry draft {list,delete}</code> commands.</li>
</ul>
<h2>v1.6.0</h2>
<ul>
<li>Fix issue where <code>// buf:lint:ignore</code> comment ignores did not work for the
<code>ENUM_FIRST_VALUE_ZERO</code> rule.</li>
<li>Add <code>buf beta studio-agent</code> command to support the upcoming Buf Studio.</li>
</ul>
<h2>v1.5.0</h2>
<ul>
<li>Upgrade to <code>protoc</code> 3.20.1 support.</li>
<li>Fix an issue where <code>buf</code> would fail if two or more roots contained
a file with the same name, but with different file types (i.e. a
regular file vs. a directory).</li>
<li>Fix check for <code>PACKAGE_SERVICE_NO_DELETE</code> to detect deleted services.</li>
<li>Remove <code>buf beta registry track</code>.</li>
<li>Remove <code>buf beta registry branch</code>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/bufbuild/buf/blob/main/CHANGELOG.md">github.com/bufbuild/buf's changelog</a>.</em></p>
<blockquote>
<h2>[v1.7.0] - 2022-06-27</h2>
<ul>
<li>Support protocol and encoding client options based on content-type in Studio Agent.</li>
<li>Add <code>--draft</code> flag to <code>buf push</code>.</li>
<li>Add <code>buf beta registry draft {list,delete}</code> commands.</li>
</ul>
<h2>[v1.6.0] - 2022-06-21</h2>
<ul>
<li>Fix issue where <code>// buf:lint:ignore</code> comment ignores did not work for the
<code>ENUM_FIRST_VALUE_ZERO</code> rule.</li>
<li>Add <code>buf beta studio-agent</code> command to support the upcoming Buf Studio.</li>
</ul>
<h2>[v1.5.0] - 2022-05-30</h2>
<ul>
<li>Upgrade to <code>protoc</code> 3.20.1 support.</li>
<li>Fix an issue where <code>buf</code> would fail if two or more roots contained
a file with the same name, but with different file types (i.e. a
regular file vs. a directory).</li>
<li>Fix check for <code>PACKAGE_SERVICE_NO_DELETE</code> to detect deleted services.</li>
<li>Remove <code>buf beta registry track</code>.</li>
<li>Remove <code>buf beta registry branch</code>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="028fdd557d"><code>028fdd5</code></a> Update to v1.7.0</li>
<li><a href="c6a545ecc0"><code>c6a545e</code></a> Run <code>make upgrade</code> (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1302">#1302</a>)</li>
<li><a href="65503feaf3"><code>65503fe</code></a> allow Dockerfile.plugin or Dockerfile (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1301">#1301</a>)</li>
<li><a href="075e294d6a"><code>075e294</code></a> add CLI support for repository draft commit (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1269">#1269</a>)</li>
<li><a href="3d2ca26216"><code>3d2ca26</code></a> ModuleReferenceForString support reference with slash (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1298">#1298</a>)</li>
<li><a href="72b51ab871"><code>72b51ab</code></a> rename CuratedPlugin options to default_options (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1300">#1300</a>)</li>
<li><a href="65c921b0b7"><code>65c921b</code></a> rename opts/options to default_opts/default_options (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1299">#1299</a>)</li>
<li><a href="0a8aec22c7"><code>0a8aec2</code></a> BSR-379: document version can be optional (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1297">#1297</a>)</li>
<li><a href="33033b8fc3"><code>33033b8</code></a> BSR-369: update plugin dependencies to a struct (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1296">#1296</a>)</li>
<li><a href="613283806d"><code>6132838</code></a> Add webhook delete and list commands to beta and fixup create (<a href="https://github-redirect.dependabot.com/bufbuild/buf/issues/1293">#1293</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/bufbuild/buf/compare/v1.4.0...v1.7.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/bufbuild/buf&package-manager=go_modules&previous-version=1.4.0&new-version=1.7.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-08-01 13:40:44 +00:00
Callum Waters
49ec3b9780 chore: lint repo (use american english) (#9144) 2022-08-01 14:24:49 +02:00
dependabot[bot]
439d84afa1 build(deps): Bump minimist from 1.2.5 to 1.2.6 in /docs (#9136)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
<details>
<summary>Commits</summary>
<ul>
<li><a href="7efb22a518"><code>7efb22a</code></a> 1.2.6</li>
<li><a href="ef88b9325f"><code>ef88b93</code></a> security notice for additional prototype pollution issue</li>
<li><a href="c2b981977f"><code>c2b9819</code></a> isConstructorOrProto adapted from PR</li>
<li><a href="bc8ecee438"><code>bc8ecee</code></a> test from prototype pollution PR</li>
<li>See full diff in <a href="https://github.com/substack/minimist/compare/1.2.5...1.2.6">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=minimist&package-manager=npm_and_yarn&previous-version=1.2.5&new-version=1.2.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/tendermint/tendermint/network/alerts).

</details>
2022-08-01 08:27:13 +00:00
dependabot[bot]
13da93a430 build(deps): Bump url-parse from 1.5.7 to 1.5.10 in /docs (#9135) 2022-08-01 10:23:39 +02:00
dependabot[bot]
476f8fa7a8 build(deps): Bump bufbuild/buf-setup-action from 1.6.0 to 1.7.0 (#9131) 2022-08-01 10:15:33 +02:00
Thane Thomson
75d51e18f7 Import latest root documentation (#9130)
Import the readme, contributing guidelines, code of conduct, security
guide and releases guide. Format all of these documents, replacing
references to `master` by references to `main`, and use Markdown link
references instead of embedded links wherever it improves legibility.

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-07-30 13:58:20 -04:00
Callum Waters
e32b86b549 docs: migrate adrs and rfcs across from master (#9115) 2022-07-30 16:57:02 +02:00
Thane Thomson
85636f6a00 Prepare main to become new default branch (#9095)
* Update Makefile with changes from #7372

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Sync main GitHub config with master and update

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove unnecesary dot folders

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Sync dotfiles

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove unused Jepsen tests for now

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* tools: remove k8s (#6625)

Remove mintnet as discussed on team call.

closes #1941

* Restore nightly fuzz testing of P2P addrbook and pex

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Fix YAML lints

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Fix YAML formatting nits

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* More YAML nits

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* github: fix linter configuration errors and occluded errors (#6400)

* Minor fixes to OpenAPI spec to sync with structs on main

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove .github/auto-comment.yml - does not appear to be used

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add issue config with link to discussions

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Adjust issue/PR templates to suit current process

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove unused RC branch config from release workflow

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Fix wildcard matching in build jobs config

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Document markdownlint config

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Restore manual E2E test group config

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Document linter workflow with local execution instructions

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Document and fix minor nit in Super-Linter markdownlint config

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update .github/ISSUE_TEMPLATE/bug-report.md

Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>

* Update pull request template to add language around discussions/issues

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* .golangci.yml: Deleted commented-out lines

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* ci: Drop "-2" from e2e-nightly-fail workflow

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Address triviality concern in PR template

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Co-authored-by: Marko <marbar3778@yahoo.com>
Co-authored-by: Sam Kleinman <garen@tychoish.com>
Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>
2022-07-29 15:20:03 -04:00
Thane Thomson
8834a0dbae Update CODEOWNERS to use teams (#9129)
* Update CODEOWNERS to use teams

Update the `CODEOWNERS` file to use the
@tendermint/tendermint-engineering and @tendermint/tendermint-research
teams as opposed to adding people one by one. This makes repository
administration somewhat easier to manage, especially when
onboarding/offboarding people.

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add Ethan as superuser

Signed-off-by: Thane Thomson <connect@thanethomson.com>
2022-07-29 15:12:28 -04:00
Mark Rushakoff
4309f54349 libs/pubsub/query: specify peg version in go.mod (#9099)
* libs/pubsub/query: specify peg version in go.mod

The code to generate the pubsub queries was dependent on an unspecified
version of the peg tool. This brings peg into go.mod so it is on a fixed
version. This should also enable dependabot to notify us of future
updates to peg.

The version of query.peg.go generated from the current version of peg
correctly contains the special "Code generated by..." line to indicate
to other tools that the file is automatically generated and should
therefore be excluded from linters, etc.

I removed the make target as there were no git grep results referencing
"gen_query_parser"; directly running "go generate" is a reasonable
expectation in Go projects.

Now that "go run" is module aware, I would typically use "go run" inside
the go:generate directive, but in this case we go build to a gitignore-d
directory in order to work around the nondeterministic output detailed
in pointlander/peg#129.

* libs/pubsub/query: check error from (*QueryParser).Init()

The newly generated peg code returns an error from Init(); the previous
version was niladic.

Co-authored-by: Sam Kleinman <garen@tychoish.com>
2022-07-27 16:35:15 -04:00
Mark Rushakoff
c4e235243b test: stop abci server started in addr test (#9093)
This test would fail if run with "go test -count=2" because it uses a
fixed address and was not closing the server, so the subsequent run
could not bind to the address.

While closing the server is correct, it would probably be better if the
API was able to report the bound address so that we could pass
"localhost:0" for an anonymous port. But I am currently focusing on test
cleanup, not ready to change any existing APIs.
2022-07-27 10:25:00 -04:00
Joonkyo Kim
18c7e3aae5 Fix unsafe-reset-all for working with default home (#9103) 2022-07-27 16:01:17 +02:00
Callum Waters
a7049ed3fc spec: migrate spec at v0.7.1. into main (#9098) 2022-07-27 00:12:36 +02:00
Callum Waters
0323bd5365 Merge branch 'main' into cal/spec-migrations 2022-07-27 00:05:03 +02:00
Callum Waters
a11b7743d4 fix mockery generation script (#9094) 2022-07-26 22:53:15 +02:00
Callum Waters
1ad0683189 Merge tag 'v0.7.1' of github.com:tendermint/spec into cal/spec-migrations
Tendermint specification version 0.7.1
2022-07-26 15:01:36 +02:00
Marko
fa2ccc80da proto: add tendermint go changes (#349)
* add missed proto files

* add abci changes

* rename blockchain to blocksync

* Update proto/tendermint/abci/types.proto

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

Co-authored-by: Callum Waters <cmwaters19@gmail.com>
2021-09-23 10:26:25 +00:00
William Banfield
60d6856782 apps.md fixups (#341)
* wip

* wip

* wip

* remove comments in favor of gh comments

* wip

* udpates to language, should must etc

* Apply suggestions from code review

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* remove tendermint cache description

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
2021-09-21 07:23:54 +00:00
Callum Waters
e2a038e039 light: update initialization description (#320) 2021-09-17 12:10:26 +02:00
Mateusz Górski
f793752d07 Update supervisor_001_draft.md (#333)
* Update supervisor_001_draft.md

If the only node in the *FullNodes* set is the primary, that was just deemed faulty, we can't find honest primary.

* Update supervisor_001_draft.md
2021-09-02 10:13:19 +02:00
William Banfield
bf71990d2f abci.md fixup (#339)
* abci: points of clarification ahead of v0.1.0

* lint++

* typo

* lint++

* double word score

* grammar

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* pr feedback

* wip

* update non-zero status code docs

* fix event description

* update CheckTx description

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
2021-09-01 17:33:35 -04:00
William Banfield
41e681293c proto: move proto files under the correct directory related to their package name (#344) 2021-08-31 17:27:55 -04:00
William Banfield
c939e155a6 abci: clarify connection use in-process (#337)
* abci: clarify connection use in-process

* Update abci.md

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* Update spec/abci/abci.md

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>

* invert abci explanations

* lint++

* lint++

* lint++

* lint++

Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
2021-08-24 14:27:19 -04:00
William Banfield
26ee62aa52 abci: clarify what abci stands for (#336)
* abci: clarify what abci stands for

* link to abci type protos.
2021-08-19 17:04:31 -04:00
Sam Kleinman
e44ab95f2f core: text cleanup (#332) 2021-08-18 13:14:38 -04:00
Mateusz Górski
4c3339ab6a Update supervisor_001_draft.md (#334) 2021-08-18 10:45:58 +00:00
Sam Kleinman
1e985f6226 rpc: update peer format in specification in NetInfo operation (#331) 2021-08-16 08:54:23 -04:00
Callum Waters
72adbf9cc9 statesync: new messages for gossiping consensus params (#328) 2021-08-09 15:41:44 +02:00
Callum Waters
8029cf7a0f evidence: add section explaining evidence (#324) 2021-08-03 11:14:28 +02:00
Callum Waters
ed7fa80693 stale bot: ignore issues (#325) 2021-07-22 11:11:04 +02:00
Marko
8f9cd23016 update proto files for release (#318) 2021-07-16 14:45:02 +00:00
Callum Waters
24f22eeb52 address discrepancies between spec and implementation (#322) 2021-07-16 12:49:15 +02:00
dependabot[bot]
f790b6f903 build(deps): bump actions/stale from 3.0.19 to 4 (#319)
Bumps [actions/stale](https://github.com/actions/stale) from 3.0.19 to 4.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v3.0.19...v4)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-15 12:58:24 +00:00
William Banfield
0ff67d6b1e update spec to reference currently used timestamp type (#317) 2021-07-14 17:10:49 -04:00
dependabot[bot]
aa8f656573 build(deps): bump gaurav-nelson/github-action-markdown-link-check (#313)
Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 1.0.12 to 1.0.13.
- [Release notes](https://github.com/gaurav-nelson/github-action-markdown-link-check/releases)
- [Commits](https://github.com/gaurav-nelson/github-action-markdown-link-check/compare/1.0.12...1.0.13)

---
updated-dependencies:
- dependency-name: gaurav-nelson/github-action-markdown-link-check
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-12 08:34:06 +00:00
Callum Waters
6039594121 add new pex messages (#312) 2021-07-07 12:48:19 +02:00
Giuliano
24222c5855 Add C++ code generation and test scenario (#310)
* add parameters to byzantine send action

* make net not trusted

it's not necessary since for proofs Ivy will assume that the environment
does not break action preconditions

* use require instead of assume

it seems that assume is not checked when other isolates call!

* add comment

* add comment

* run with random seed

* make domain model extractable to C++

* substitute require for assume

assumes in an action are not checked when the action is called! I.e.
they place no requirement on the caller; we're just assuming that the
caller is going to do the right thing. This wasn't very important here
but it leade to a minor inconsistency slipping through.

* make the net isolate not trusted

there was no need for it

* add tendermint_test.ivy

contains a simple test scenario that show that the specification is no
vacuuous

* update comment

* add comments

* throw if trying to parse nset value in the repl

* add comment

* minor refactoring
2021-07-07 12:46:23 +02:00
crypto-facs
6bd5263515 rpc: Add totalGasUSed to block_results response (#308) 2021-06-24 15:01:36 +00:00
Aleksandr Bezobchuk
89d381f7cf update ResponseCheckTx (#306) 2021-06-07 09:35:47 -04:00
Sam Kleinman
5559e14355 rpc: add chunked genesis endpoint (#299)
* rpc: add chunked genesis endpoint

* fix lint

* feedback

* add info about error

* fix lint

Co-authored-by: marbar3778 <marbar3778@yahoo.com>
2021-06-03 09:46:21 +00:00
Marko
a2a9ffbe7e rpc: clarify timestamps (#304)
* clarify timestamps

* changelog entry

* Update spec/rpc/README.md

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

Co-authored-by: Callum Waters <cmwaters19@gmail.com>
2021-06-02 12:03:33 +00:00
Marko
8dd91a7ac3 add a changelog to track changes (#303)
* add a changelog to track changes

* Update CHANGELOG.md

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

Co-authored-by: Callum Waters <cmwaters19@gmail.com>
2021-05-27 11:04:37 +00:00
Yixin Luo
f3216e6953 rename HasVote to ReceivedVote (#289) 2021-05-25 07:42:30 +00:00
dependabot[bot]
90434cb74d build(deps): bump actions/stale from 3.0.18 to 3.0.19 (#302)
Bumps [actions/stale](https://github.com/actions/stale) from 3.0.18 to 3.0.19.
- [Release notes](https://github.com/actions/stale/releases)
- [Commits](https://github.com/actions/stale/compare/v3.0.18...v3.0.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-25 07:37:38 +00:00
dependabot[bot]
aba090a69a build(deps): bump actions/stale from 3 to 3.0.18 (#300)
Bumps [actions/stale](https://github.com/actions/stale) from 3 to 3.0.18.
- [Release notes](https://github.com/actions/stale/releases)
- [Commits](https://github.com/actions/stale/compare/v3...v3.0.18)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-20 10:50:56 +00:00
Sam Kleinman
048f6a32f9 lint: fix lint errors (#301) 2021-05-12 18:33:24 -04:00
MengXiangJian
4a9bcebe2a fix message type for block-sync (#298) 2021-05-12 11:28:40 +02:00
Jordan Sexton
4b79bccc0b Fixed a broken link (#291) 2021-05-07 14:29:12 -04:00
Giuliano
292828a01b A few improvements to the Ivy proof (#288)
* Avoid quantifier alternation cycle

The problematic quantifier alternation cycle arose because the
definition of accountability_violation was unfolded.

This commit also restructures the induction proof for clarity.

* add count_lines.sh

* fix typo and add forgotten complete=fo in comment

Co-authored-by: Giuliano <giuliano@eic-61-11.galois.com>
2021-05-04 14:28:07 +02:00
Marko
5dfaa54350 rpc: define spec for RPC (#276)
* add rpc spec and support outline

* add json

* add more routes remove unneeded ones

* add rest of rpc endpoints

* add jsonrpc calls

* add more jsonrpc calls

* fix blockchain

* cleanup unused links and add links to repos

* Update spec/rpc/README.md

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

* add missing param from consensus param

* Update spec/rpc/README.md

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

* Update spec/rpc/README.md

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

* fix cast and add doc to readme

Co-authored-by: Callum Waters <cmwaters19@gmail.com>
Co-authored-by: Marko Baricevic <markobaricevic@Fergalicious.local>
2021-04-27 09:25:32 +00:00
Ethan Buchman
00446bb9f4 Update README.md (#286) 2021-04-23 19:52:48 +00:00
Callum Waters
255942e8c7 p2p: update state sync messages for reverse sync (#285) 2021-04-23 13:22:09 +02:00
Callum Waters
84ee4249ae core: update a few sections (#284) 2021-04-20 10:21:27 +02:00
Callum Waters
b39af911ae RFC: ReverseSync - fetching historical data (#224) 2021-04-19 17:02:09 +02:00
Dev Ojha
0dc5d4df07 ABCI++ RFC (#254)
* ABCI++ RFC

This commit adds an RFC for ABCI++, which is a collection of three new phases of communication between the consensus engine and the application.

Co-authored-by: Sunny Aggarwal <sunnya97@protonmail.ch>

* Fix bugs pointed out by @liamsi

* Update rfc/004-abci++.md

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Fix markdown lints

* Update rfc/004-abci++.md

Co-authored-by: Ismail Khoffi <Ismail.Khoffi@gmail.com>

* Update rfc/004-abci++.md

Co-authored-by: Tess Rinearson <tess.rinearson@gmail.com>

* Update rfc/004-abci++.md

Co-authored-by: Tess Rinearson <tess.rinearson@gmail.com>

* Add information about the rename in the context section

* Bold RFC

* Add example for self-authenticating vote data

* More exposition of the term IPC

* Update pros / negatives

* Fix sentence fragment

* Add desc for no-ops

Co-authored-by: Sunny Aggarwal <sunnya97@protonmail.ch>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Ismail Khoffi <Ismail.Khoffi@gmail.com>
Co-authored-by: Tess Rinearson <tess.rinearson@gmail.com>
2021-04-09 10:33:45 +00:00
Sam Kleinman
ea8238f090 abci: reorder sidebar (#282) 2021-04-06 06:59:57 +00:00
istoilkovska
640b71038b Proposer-based timestamp specification (#261)
* added proposer-based timestamp spec

* Update spec/consensus/proposer-based-timestamp/pbts_001_draft.md

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Update spec/consensus/proposer-based-timestamp/pbts_001_draft.md

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Update spec/consensus/proposer-based-timestamp/pbts-algorithm_001_draft.md

Co-authored-by: Marko <marbar3778@yahoo.com>

* Update spec/consensus/proposer-based-timestamp/pbts-algorithm_001_draft.md

* Update spec/consensus/proposer-based-timestamp/pbts-sysmodel_001_draft.md

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

* fixes from PR

Co-authored-by: Josef Widder <44643235+josef-widder@users.noreply.github.com>
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Marko <marbar3778@yahoo.com>
Co-authored-by: Callum Waters <cmwaters19@gmail.com>
2021-03-23 16:40:21 +01:00
Marko
5c32ebcda8 p2p: links (#268)
* fix links

* fix more links
2021-03-23 11:13:42 +00:00
Marko
b2465e0c3a genesis: Explain fields in genesis file (#270)
* describe the genesis

* Update spec/core/genesis.md

Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

* add wording on app_state

* Update spec/core/genesis.md

Co-authored-by: Callum Waters <cmwaters19@gmail.com>

Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>
Co-authored-by: Callum Waters <cmwaters19@gmail.com>
2021-03-23 10:13:02 +00:00
Marko
9f6a4bcf23 readme: cleanup (#262)
* modify readme

* add rfc and proto

* add rust=spec back to avoid breakage

* lint readme
2021-03-17 13:51:10 +00:00
Ethan Buchman
b4a31746dd Fix list of RFCs (#266) 2021-03-17 08:43:54 +01:00
Marko
b270ab8d15 spec: merge rust-spec (#252) 2021-03-01 08:54:08 +00:00
Ethan Buchman
227e5269ca abci: note on concurrency (#258)
Co-authored-by: Marko <marbar3778@yahoo.com>
2021-02-26 10:30:09 +00:00
Marko
b315f04980 proto: modify height int64 to uint64 (#253) 2021-02-16 13:06:00 +00:00
Marko
abaffef912 proto: add files (#246)
Co-authored-by: Erik Grinaker <erik@interchain.berlin>
2021-01-28 12:10:22 +00:00
Marko
038f3e025a params: remove block timeiota (#248) 2021-01-27 11:29:54 +00:00
Igor Konnov
2f590a6392 non-critical bugfix in the TLA+ spec (found by new version of apalache) (#244) 2021-01-21 11:50:06 +01:00
Marko
72d15a4b07 spec: remove reactor section (#242)
Co-authored-by: Tess Rinearson <tess.rinearson@gmail.com>
2021-01-19 16:28:05 +01:00
Josef Widder
1b2b24055c Update supervisor_001_draft.md (#243) 2021-01-15 13:39:36 +01:00
Marko
d260ff3e37 abci: rewrite to proto interface (#237) 2021-01-12 15:15:37 +01:00
Marko
a4672048e7 reactors: remove bcv1 (#241) 2021-01-11 18:23:40 +01:00
Marko
fc569173a1 layout: add section titles (#240) 2021-01-11 18:23:18 +01:00
dependabot[bot]
ce146d00d7 build(deps): bump gaurav-nelson/github-action-markdown-link-check (#239)
Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/gaurav-nelson/github-action-markdown-link-check/releases)
- [Commits](https://github.com/gaurav-nelson/github-action-markdown-link-check/compare/1.0.11...0fe4911067fa322422f325b002d2038ba5602170)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-11 12:12:49 +01:00
Anton Kaliaev
439a5bcacb p2p: update frame size (#235)
Reflect the change made in https://github.com/tendermint/tendermint/pull/5805

The MTU (Maximum Transmission Unit) for Ethernet is 1500 bytes.
The IP header and the TCP header take up 20 bytes each at least (unless
optional header fields are used) and thus the max for (non-Jumbo frame)
Ethernet is 1500 - 20 -20 = 1460
Source: https://stackoverflow.com/a/3074427/820520
2020-12-18 12:19:38 +01:00
Josef Widder
accd7ffe18 Update README.md (#234) 2020-12-16 13:27:23 +01:00
Josef Widder
42751ea4f3 Computing attack types (#232)
Add light attack evidence handling
2020-12-15 18:45:26 +01:00
dependabot[bot]
acb9a7d734 build(deps): bump gaurav-nelson/github-action-markdown-link-check (#233)
Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 1.0.8 to 1.0.11.
- [Release notes](https://github.com/gaurav-nelson/github-action-markdown-link-check/releases)
- [Commits](https://github.com/gaurav-nelson/github-action-markdown-link-check/compare/1.0.8...2a60e0fe41b5361f446ccace6621a1a2a5c324cf)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 21:53:43 +01:00
Igor Konnov
31cfa53082 The TLA+ specification of the attackers detection (#231)
* the working attackers isolation spec, needs more comments

* the TLA+ spec of the attackers isolation
2020-12-11 15:03:48 +01:00
Josef Widder
26ef2ccddb Draft of evidence handling for discussion (#225)
* start with accountability deliverable

* problem statement

* draft function

* quite complete draft. ready to discuss with Igor

* Update isolate-attackers_001_draft.md

* Update isolate-attackers_001_draft.md

* Update isolate-attackers_001_draft.md

* Update isolate-attackers_001_draft.md

* Update isolate-attackers_001_draft.md

* ready for TLA+ to take over

* isolate

* isolateamnesiatodos

* Update isolate-attackers_001_draft.md

* Update rust-spec/lightclient/attacks/isolate-attackers_001_draft.md

Co-authored-by: Igor Konnov <konnov@forsyte.at>

* Update rust-spec/lightclient/attacks/isolate-attackers_001_draft.md

Co-authored-by: Igor Konnov <konnov@forsyte.at>

* Update rust-spec/lightclient/attacks/isolate-attackers_001_draft.md

Co-authored-by: Igor Konnov <konnov@forsyte.at>

* Update rust-spec/lightclient/attacks/isolate-attackers_001_draft.md

Co-authored-by: Igor Konnov <konnov@forsyte.at>

* Update rust-spec/lightclient/attacks/isolate-attackers_001_draft.md

Co-authored-by: Igor Konnov <konnov@forsyte.at>

* Update rust-spec/lightclient/attacks/isolate-attackers_001_draft.md

Co-authored-by: Igor Konnov <konnov@forsyte.at>

* Update rust-spec/lightclient/attacks/isolate-attackers_001_draft.md

Co-authored-by: Igor Konnov <konnov@forsyte.at>

* Update rust-spec/lightclient/attacks/isolate-attackers_001_draft.md

Co-authored-by: Igor Konnov <konnov@forsyte.at>
2020-12-11 14:34:16 +01:00
Shahan Khatchadourian
6abcb13dab BFT requires _less than_ 1/3 faulty validators (#228)
Thanks fo spotting the imprecision in the text, @shahankhatch !
2020-12-02 12:01:18 +01:00
Marko
033608bbf1 abci: add abci_version to requestInfo (#223) 2020-11-24 15:15:08 +01:00
Marko
871d0514cd abci: lastcommitinfo.round extra sentence (#221) 2020-11-17 10:33:01 +01:00
Igor Konnov
c1ff62fe44 Light client detector spec in TLA+ and refactoring of light client verification TLA+ spec (#216)
Add light client detector spec in TLA+
2020-11-09 11:08:33 +01:00
Giuliano
66e9106b4d add Ivy proofs (#210)
* add Ivy proofs

* fix docker-compose command
2020-11-09 11:05:26 +01:00
Josef Widder
d5e0294003 Detector English Spec ready (#215)
Add detector English spec
2020-11-09 11:03:20 +01:00
Marko
32b811a1fb encoding: add secp, ref zip215, tables (#212) 2020-11-09 09:53:00 +01:00
Callum Waters
819e89ac7a evidence: update data structures to reflect added support of abci evidence (#213) 2020-11-06 09:41:24 +01:00
Marko
cf03759ff5 docs: make blockchain not viewable (#211) 2020-11-05 12:17:11 +01:00
Marko
9fce8480b0 Core: move validation & data structures together (#176)
Co-authored-by: Callum Waters <cmwaters19@gmail.com>
2020-11-05 10:09:59 +01:00
Marko
d31a4a4b34 RFC: adopt zip 215 (#144)
Co-authored-by: Robert Zaremba <robert@zaremba.ch>
2020-11-05 09:57:08 +01:00
Josef Widder
9ad6440bc0 Sequential Supervisor (#186)
* move from tendermint-rs but needs discussion

* markdown lint

* TODO links replaced

* links

* links

* links lint

* Update rust-spec/lightclient/supervisor/supervisor.md

* Update rust-spec/lightclient/supervisor/supervisor.md

* Update rust-spec/lightclient/supervisor/supervisor.md

* Update rust-spec/lightclient/supervisor/supervisor.md

* moved peer handling definitions to supervisor

* polishing

* rename

* Update rust-spec/lightclient/supervisor/supervisor_001_draft.md

* Update rust-spec/lightclient/supervisor/supervisor_001_draft.md

* changes to maintain StateVerified again

* ready for changes in verification

* start of supervisor

* module name

* fixed

* more details

* supevisor completed. Now I have to add function to verification

* ready for review

* tla comment

* removed issues

* Update rust-spec/lightclient/supervisor/supervisor_001_draft.md

* intro text fixed

* indentation

* Update rust-spec/lightclient/supervisor/supervisor_001_draft.md

* comment to entry points

Co-authored-by: Marko Baricevic <marbar3778@yahoo.com>
2020-11-02 17:35:25 +01:00
Marko
97928e190a github: issue template for proposals (#190) 2020-11-02 16:06:17 +01:00
Josef Widder
ec8af314cc spec: update light client verification to match supervisor (#171)
* VDD renaming of verification spec + links fixed

* latest()

* backwards

* added TODOs

* link in old file to new name

* better text

* revision done. needs one more round of reading

* renamed constants in 001 according to TLA+ and impl

* ready for PR

* forgot linting

* Update rust-spec/lightclient/verification/verification_002_draft.md

* Update rust-spec/lightclient/verification/verification_002_draft.md

* added lightstore function needed for supervisor

* added lightstore functions for supervisor

* ident

* Update rust-spec/lightclient/verification/verification_002_draft.md
2020-10-22 14:26:56 +02:00
dependabot[bot]
a3fadb7c1a build(deps): bump gaurav-nelson/github-action-markdown-link-check from 1.0.7 to 1.0.8 (#188)
Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 1.0.7 to 1.0.8.
- [Release notes](https://github.com/gaurav-nelson/github-action-markdown-link-check/releases)
- [Commits](https://github.com/gaurav-nelson/github-action-markdown-link-check/compare/1.0.7...e3c371c731b2f494f856dc5de7f61cea4d519907)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-21 13:15:32 +02:00
Sam Hart
01622f81e9 Update README.md (#185) 2020-10-14 17:08:20 +02:00
Igor Konnov
792767d1cb Extending the blockchain specification (in the light client) to produce different ratios of faults (#183)
* cleaning unused definitions

* introduced the ratio of faulty processes
2020-10-08 10:42:00 +02:00
Josef Widder
0794fc8ff2 first check latest with secondary (#184) 2020-10-08 09:51:00 +02:00
Marko
c5576dfa69 spec: protobuf changes (#156)
Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
2020-10-06 12:40:25 +02:00
Marko
04fb20e33d remove setOption (#181) 2020-10-05 08:54:41 +02:00
Josef Widder
8391fa0b89 TLA+ specs from MBT revision (#173) 2020-10-01 11:31:53 +02:00
Marko
3e56eb5fe3 fix markdown linter (#172) 2020-09-29 14:23:40 +02:00
Callum Waters
733b020899 evidence: update data structures (#165) 2020-09-29 14:05:44 +02:00
Andrey Kuprianov
109a73f672 describe valset sorting according to v0.34 requirements (#169) 2020-09-25 09:22:14 +02:00
Josef Widder
80747a0872 fixed an overlooked conflict (#167) 2020-09-24 09:59:24 +02:00
Josef Widder
f3033c5515 spec: Light client attack detector (#164)
* start with new detection and evidence spec

* more definitions at top

* sketch of functions

* pre post draft

* evidence proof

* typo

* evidence theory polished

* some TODOs resolved

* more TODOs

* links

* second to last revision before PR

* links

* I will read once more and then make a PR

* removed peer handling definitions

* secondary

* ready to review

* detector ready for review

* Update rust-spec/lightclient/detection/detection.md

Co-authored-by: Zarko Milosevic <zarko@informal.systems>

* Update rust-spec/lightclient/detection/detection.md

Co-authored-by: Zarko Milosevic <zarko@informal.systems>

* Update rust-spec/lightclient/detection/detection.md

Co-authored-by: Zarko Milosevic <zarko@informal.systems>

* Update rust-spec/lightclient/detection/detection.md

Co-authored-by: Zarko Milosevic <zarko@informal.systems>

* Update rust-spec/lightclient/detection/detection.md

Co-authored-by: Zarko Milosevic <zarko@informal.systems>

* Update rust-spec/lightclient/detection/detection.md

Co-authored-by: Zarko Milosevic <zarko@informal.systems>

* Update rust-spec/lightclient/detection/detection.md

* skip-trace

* PossibleCommit explained

* Update rust-spec/lightclient/detection/detection.md

Co-authored-by: Zarko Milosevic <zarko@informal.systems>

* comments by Zarko

* renamed and changed link in README

Co-authored-by: Zarko Milosevic <zarko@informal.systems>
2020-09-24 09:53:50 +02:00
Anton Kaliaev
6c95c3f250 spec/reactors/mempool: batch txs per peer (#155)
* spec/reactors/mempool: batch txs per peer

Refs https://github.com/tendermint/tendermint/issues/625

* update
2020-09-10 21:56:00 +02:00
Josef Widder
a66bb37e32 Update README.md (#160) 2020-09-10 15:07:24 +02:00
Josef Widder
606abc7fc0 Fastsync spec from tendermint-rs (#157)
* fastsync spec from tendermint-rs

* fixed broken link

* fixed linting

* more fixes

* markdown lint

* move fast_sync to rust-spec

Co-authored-by: Marko Baricevic <marbar3778@yahoo.com>
2020-09-10 13:03:50 +02:00
Josef Widder
b74b1c2b68 Current versions of light client specs from tendermint-rs (#158)
* current versions of light client specs from tendermint-rs

* markdown lint

* linting

* links

* links

* links

Co-authored-by: Marko Baricevic <marbar3778@yahoo.com>
2020-09-10 12:56:15 +02:00
Marko
dd325bb191 add a stale bot (#134) 2020-09-10 10:41:28 +02:00
Marko
d8a2c8f6f1 spec: remove evidences (#153) 2020-09-02 18:17:11 +02:00
Marko
1075f77cc3 spec: extract light-client to its own directory (#152)
Co-authored-by: Callum Waters <cmwaters19@gmail.com>
2020-09-01 10:47:14 +02:00
Marko
45bbbb6317 spec: update abci events (#151) 2020-09-01 10:05:34 +02:00
Marko
6140847bba docs: add sections to abci (#150) 2020-08-31 15:50:07 +02:00
dependabot[bot]
cda8006569 build(deps): bump gaurav-nelson/github-action-markdown-link-check from 0.6.0 to 1.0.7 (#149)
Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 0.6.0 to 1.0.7.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-08-24 13:54:15 +02:00
Marko
9dbf818055 ci: add dependabot config (#148) 2020-08-24 13:52:22 +02:00
Marko
efbbc9462f ci: add markdown linter (#146) 2020-08-24 11:47:31 +02:00
Tess Rinearson
c9d3564634 remove unused directories and update README (#145)
This change removes unused directories (`papers` and `research`) 
and updates the README to reflect our strategy for merging the 
informalsystems/tendermint-rs specs into this repository.

Partially addresses #121.
2020-08-21 12:40:31 +02:00
Erik Grinaker
8dd2ed4c6f update ResponseInitChain.app_hash description (#143) 2020-08-13 13:05:12 +02:00
Erik Grinaker
f3207cee52 add description of arbitrary initial height (#135) 2020-08-13 10:45:05 +02:00
Erik Grinaker
a84c59734f accept RFC-002 (#142) 2020-08-13 10:44:27 +02:00
Callum Waters
430a4d0504 update evidence verification (#139) 2020-08-12 14:19:09 +02:00
Erik Grinaker
89ac8f6e62 update hashing of empty inputs, and initial block LastResultsHash (#141) 2020-08-11 16:52:23 +02:00
Erik Grinaker
95acfdead1 abci: add ResponseInitChain.app_hash (#140) 2020-08-11 16:48:22 +02:00
Erik Grinaker
604923e034 RFC-002: non-zero genesis (#119) 2020-08-11 13:28:59 +02:00
Callum Waters
713a773c81 Evidence time is sourced from block time (#138) 2020-08-10 21:20:24 +02:00
Erik Grinaker
e96921822d spec: revert event hashing (#132) 2020-08-06 11:10:11 +02:00
Sean Braithwaite
29f4e13e05 Merge pull request #130 from tendermint/marko/bring_blockchain_back
spec: bringing blockchain back
2020-08-03 17:48:34 +02:00
Marko Baricevic
ef1e0ff886 add correct links 2020-08-03 10:52:05 +02:00
Marko Baricevic
c5e45ecb48 bring blockchain back 2020-08-03 10:48:38 +02:00
Callum Waters
31b182b7aa update spec with the removal of phantom validator evidence (#126) 2020-07-31 12:03:44 +02:00
Sean Braithwaite
d46cd7f573 Merge pull request #125 from tendermint/anton/2769-canonical
spec/consensus: canonical vs subjective commit
2020-07-30 12:00:54 +02:00
Anton Kaliaev
0445156ed9 Apply suggestions from code review
Co-authored-by: Igor Konnov <igor.konnov@gmail.com>
2020-07-29 15:45:46 +04:00
Anton Kaliaev
3a29521848 spec/consensus: canonical vs subjective commit
Refs https://github.com/tendermint/tendermint/issues/2769
2020-07-29 15:13:15 +04:00
Marko
2bd673c8eb blockchain: remove duplicate evidence sections (#124) 2020-07-29 08:24:42 +02:00
Marko
8ff136c716 blockchain: rename to core (#123) 2020-07-28 16:51:14 +02:00
Anton Kaliaev
b10ff00e1b spec/abci: expand on Validator#Address (#118)
Refs https://github.com/tendermint/tendermint/issues/3732
2020-07-22 16:50:24 +04:00
Erik Grinaker
6b570e2111 abci: tweak node sync estimate (#115) 2020-07-10 20:16:13 +02:00
Anton Kaliaev
89922df775 abci: add AppVersion to ConsensusParams (#106) 2020-06-23 12:19:37 +04:00
Callum Waters
1bd2aacb56 spec: update evidence in blockchain.md (#108)
now evidence reflects the actual evidence present in the tendermint repo
2020-06-19 15:50:26 +02:00
Alexander Simmerl
30ef12d0bb spec: link to abci server implementations (#100) 2020-06-15 10:42:48 +02:00
Anton Kaliaev
199124048e spec: modify Header.LastResultsHash (#97)
Refs: https://github.com/tendermint/tendermint/issues/1007
PR: https://github.com/tendermint/tendermint/pull/4845
2020-06-12 14:41:51 +04:00
Callum Waters
9c0754e617 spec: add ProofTrialPeriod to EvidenceParam (#99) 2020-06-11 10:10:06 +02:00
Anton Kaliaev
0d5f212f30 reactors/pex: masked IP is used as group key (#96) 2020-05-25 09:32:55 +04:00
Callum Waters
5acd1540c0 Update evidence params with MaxNum (#95)
evidence params now includes maxNum which is the maximum number of evidence that can be committed on a single block
2020-05-12 13:41:44 +02:00
Tess Rinearson
d65205ecad document state sync ABCI interface and P2P protocol (#93)
* Revert "Revert "document state sync ABCI interface and P2P protocol (#90)" (#92)"

This reverts commit 90797cef90.

* update with new enum case

* fix links

Co-authored-by: Erik Grinaker <erik@interchain.berlin>
2020-05-11 09:27:37 +04:00
Anton Kaliaev
3c27335db3 reactors/pex: specify hash function (#94)
https://github.com/tendermint/tendermint/pull/4810/files
2020-05-08 22:15:08 +04:00
Anton Kaliaev
c3cd54a8e0 blockchain: change validator set sorting method (#91)
* abci: specify sorting of RequestInitChain.Validators

* blockchain: change validator sorting method

Refs https://github.com/tendermint/tendermint/issues/2478
2020-05-06 11:02:20 +04:00
Tess Rinearson
90797cef90 Revert "document state sync ABCI interface and P2P protocol (#90)" (#92)
This reverts commit 9842b4b0fb.
2020-05-05 14:53:49 +02:00
Erik Grinaker
9842b4b0fb document state sync ABCI interface and P2P protocol (#90)
The corresponding Tendermint PRs are tendermint/tendermint#4704 and tendermint/tendermint#4705.
2020-05-05 14:40:00 +02:00
Anton Kaliaev
f399abd7ac abci: update MaxAgeNumBlocks & MaxAgeDuration docs (#88) 2020-04-21 17:15:26 +02:00
Anton Kaliaev
7a0cdd53d5 abci: add MaxAgeNumBlocks/MaxAgeDuration to EvidenceParams (#87) 2020-04-14 14:46:21 +04:00
Erik Grinaker
ebda9dcac5 abci: add basic description of ABCI Commit.ResponseHeight (#85)
Documentation for block pruning, once it's merged: tendermint/tendermint#4588.

Minimum documentation, for now - we probably shouldn't encourage using this feature too much until we release state sync.
2020-04-14 10:54:25 +04:00
Erik Grinaker
15b15d2060 accept RFC-001 (#86) 2020-04-03 13:07:57 +02:00
Erik Grinaker
3ab6026ad7 RFC-001: configurable block retention (#84)
* Added RFC for truncated block history coordination

* Clarified minimum block retention

* Added hard checks on block retention and snapshot interval, and made some minor tweaks

* Genesis parameters are immutable

* Use local config for snapshot interval

* Reordered parameter descriptions

* Clarified local config option for snapshot-interval

* rewrite for ABCI commit response

* Renamed RFC

* add block retention diagram

* Removed retain_blocks table

* fix image numbers

* resolved open questions

* image quality
2020-04-02 15:38:00 +02:00
Marko
1152120dea remove .idea dir (#83)
Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>
2020-03-19 12:20:44 +01:00
Marko
d45389e2b0 codeowners: add code owners (#82)
* codeowners: add code owners

- added some codeowners
please comment if youd like to be added as well.

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>

* remove comment of repo maintainers
2020-03-15 17:37:25 +01:00
Callum Waters
9440fc16ce Merge pull request #81 from tendermint/callum/markdown-link-checker
Add markdown link checker
2020-03-10 16:27:21 +01:00
Callum Michael Waters
3f04e8bbce second attempt at fixing all links 2020-03-10 16:22:14 +01:00
Callum Michael Waters
c9a664a2f8 first attempt at fixing all links 2020-03-10 16:15:59 +01:00
Callum Waters
4f0fb3325a removed folder-path flag 2020-03-10 15:51:23 +01:00
Callum Waters
e963deff5a changed tab spacing 2020-03-10 15:48:31 +01:00
Callum Michael Waters
ee5c790878 add markdown link checker 2020-03-10 15:32:51 +01:00
Callum Waters
327767a1c1 Merge pull request #80 from tendermint/callum/link-pex-reactor
update link to the pex reactor
2020-03-10 15:04:27 +01:00
Callum Waters
edb4928357 update link to the pex reactor 2020-03-10 14:41:17 +01:00
Marko
b0f35a64d9 evidence: Add time to evidence params (#69)
* evidence: Add time to evidence params

- this pr is grouped together with https://github.com/tendermint/tendermint/pull/4254, once that PR is merged then this one can be as well.

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>

* remove note

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>

* Apply suggestions from code review

Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>

Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
2020-02-23 14:09:58 +01:00
Marko
56ffcf709a docs: update specs to remove cmn (#77)
- cmn was remvoed in favor of sub pkgs. cmn.kvpair is now kv.pair

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>
2020-02-03 18:37:09 +01:00
Zaki Manian
452f0b775a p2p: Merlin based malleability fixes (#72)
* Update the secret connection spec with the use of merlin to eliminte handshake malleability

* Update spec/p2p/peer.md

Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>

* Update spec/p2p/peer.md

Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>

* Update spec/p2p/peer.md

Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>

Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
2020-01-27 11:34:53 +04:00
Zarko Milosevic
cf24489764 Merge pull request #76 from tendermint/ismail/fix-link-light
Fix link in readme
2020-01-24 15:31:11 +01:00
Ismail Khoffi
576e40eabd Fix link in readme
./light -> ./light-client
2020-01-24 15:17:04 +01:00
Zarko Milosevic
206139f384 Merge pull request #75 from tendermint/bucky/lite-light
lite->light
2020-01-23 23:28:51 +01:00
Ethan Buchman
603364bdaa lite->light 2020-01-23 09:22:40 -08:00
Zarko Milosevic
033a0cb53f Merge pull request #61 from tendermint/zm_lite_client_algo
Update specification of light client algorithm to align with the code
2020-01-23 14:50:49 +01:00
Zarko Milosevic
026fddee4f Aligh the correctness arguments with the pseudocode changes 2020-01-23 14:49:45 +01:00
Zarko Milosevic
dc542068ae Merge pull request #73 from tendermint/bucky/light-reorg
Move light specs to their own dir, add readme and diagram
2020-01-23 11:14:38 +01:00
Ethan Buchman
c35d6e706f update readme 2020-01-22 13:52:54 -08:00
Ethan Buchman
bd2f41bf79 fix image 2020-01-22 13:49:09 -08:00
Ethan Buchman
d1bd98d5e0 detection TODO 2020-01-22 13:19:24 -08:00
Ethan Buchman
035838901e add diagram 2020-01-22 13:17:16 -08:00
Ethan Buchman
e342c21336 add redirects 2020-01-22 13:10:08 -08:00
Ethan Buchman
eb9e1f961c titles 2020-01-22 13:06:49 -08:00
Ethan Buchman
f26eb4ee89 light client dir and readmes 2020-01-22 12:55:31 -08:00
Zarko Milosevic
146e251892 Address reviewer comment's. Intermediate commit 2020-01-08 17:49:32 +01:00
Zarko Milosevic
7130c2e68c Removing Store from API and providing end-to-end timing guarantees 2020-01-06 18:30:59 +01:00
Zarko Milosevic
4a9eb1f1ac Intermediate commit (aligning spec with the code) 2019-12-31 13:31:35 +01:00
Zarko Milosevic
0adde9d415 Separating algorithm from proofs 2019-12-26 13:11:01 +01:00
Zarko Milosevic
ee0cc537b8 Addressing reviewer's comments 2019-12-25 13:58:27 +01:00
Zarko Milosevic
4f7c55507c Address reviewer's comments 2019-12-12 12:37:36 +01:00
Zarko Milosevic
8528cdb314 Merge remote-tracking branch 'remotes/origin/master' into zm_lite_client_algo
# Conflicts:
#	spec/consensus/light-client.md
2019-12-11 16:18:17 +01:00
Zarko Milosevic
9ddfc79813 Add explanation on difference between trusted models 2019-12-11 16:13:47 +01:00
Zarko Milosevic
069906a25d Improve algorithms 2019-12-11 15:20:14 +01:00
Zarko Milosevic
5c580846bb Improved error handling 2019-12-06 15:56:05 +01:00
Anca Zamfir
afda2d39b6 some suggestions for pseuodocode changes 2019-12-06 12:43:16 +01:00
Sunny Aggarwal
743a658613 Add sr25519 amino documentation (#67)
* sr25519 amino

* Update spec/blockchain/encoding.md

Co-Authored-By: Marko <marbar3778@yahoo.com>
2019-12-04 12:44:28 +01:00
dongsamb
dbc8765104 Add spec doc about unconditional_peer, persistent_peers_max_dial of ADR-050 (#68)
* Add spec doc about unconditional_peer_ids, persistent_peers_max_dial_period of ADR-050

* Add indefinitely dialing condition
2019-12-04 09:09:24 +01:00
Zarko Milosevic
2306108d8a Apply suggestions from code review
Co-Authored-By: Anca Zamfir <ancazamfir@users.noreply.github.com>
2019-12-02 12:40:47 +01:00
Zarko Milosevic
4ee393c3da Clean up error conditions and simplify pseudocode 2019-11-28 15:42:35 +01:00
Anton Kaliaev
953523c3cb reflect breaking changes made to Commit (#63)
* reflect breaking changes made to Commit

PR: https://github.com/tendermint/tendermint/pull/4146
Issue: https://github.com/tendermint/tendermint/issues/1648

* types: rename Commit#Precommits to Signatures

* update BlockIDFlagAbsent comment

* remove iota
2019-11-23 11:02:08 +01:00
Zarko Milosevic
d862fd4ec7 Merge pull request #56 from tendermint/zm_fix_system_model
Fix model section
2019-11-21 12:53:20 +01:00
Marko
7b3138e694 spec: update spec with tendermint updates (#62)
* spec: update spec with tendermint updates

- this in preperation of deleting the spec folder in docs in tendermint/tendermint

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>

* spec: added in reactors & p2p

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>

* spec: update readme in spec to comply with docs site

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>

* docs: addded more changes from tednermint/tendermint

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>
2019-11-21 11:15:24 +01:00
Zarko Milosevic
a4b68ec2fb Add non-recursive specification of Bisection algorithm
- Fix timing issues by introducing Delta parameter
2019-11-15 12:47:48 +01:00
Zarko Milosevic
f618acf2ab Fix model section 2019-10-29 12:01:13 +01:00
Marko
513c67230f Add Section for P2P (#53)
* Add Section for P2P

- moved over the section on p2p

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>

* add some more files

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>
2019-10-07 15:02:20 +02:00
Marko
fa3430ad16 spec/consensus/signing: add more details about nil and amnesia (#54)
- Add more details about nil votes and about amnesia attacks

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>
2019-10-02 15:28:56 -07:00
Marko
95cf253b6d Add ABCI SPEC (#51)
- move the abci spec from tendermint to spec repo

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>
2019-09-17 16:07:08 +02:00
Marko
9b3531d7d6 Add consesnus and blockchain specs, (#52)
- Open questions
	- Do  we want to split lite client work from consesnsus
	- From the blockchain spec, is encoding nessecary in the spec

Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>
2019-09-17 16:06:20 +02:00
Marko
81a0198af2 This PR is to create signed commits to be able to merge (#50)
Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>
2019-09-14 19:56:17 +02:00
Marko
87abbf78e6 Prepare to Nuke Develop (#47)
* state -> step

* vote -> v

* New version of the algorithm and the proof

* New version of the algorithm and the proofs

* Added algorithm description

* Add algorithm description

* Add introduction

* Add conclusion

* Add conclusion file

* fix warnings (caption was defined twice)

- only the latter is used anyways (centers captions)
- this makes it possible to autom. building the paper

* Update grammar

* s/state_p/step_p

* Address Ismail's comments

* intro: language fixes

* definitions: language fixes

* consensus: various fixes

* proof: some fixes

* try to improve reviewability

* \eq -> =

* textwrap to 79

* various minor fixes

* proof: fix itemization

* proof: more minor fixes

* proof: timeouts are functions

* proof: fixes to lemma6

* Intro changes and improve title page

* Add Marko and Ming to acks

* add readme

* Format algorithm correctly

Clarify condition semantic and timeouts

Improve descriptions

* patform -> platform

* Ensure that rules are mutually exclusive

- various clarifications and small improvements

* Release v0.6

* small nits for smoother readability
2019-09-03 14:07:40 +02:00
milosevic
b362894a56 Merge pull request #8 from tendermint/align-algorithm-with-code
Align protocol with Tendermint code and add find valid value mechanism
2017-12-06 09:52:32 +01:00
Zarko Milosevic
2866ba1a2c Align protocol with Tendermint code and add find valid value mechanism 2017-12-06 09:48:53 +01:00
milosevic
5764a81410 Merge pull request #1 from tendermint/feature/add-timeouts
Add three timeouts and align pseudocode better with existing algorithm
2017-09-11 09:18:07 +02:00
Milosevic, Zarko
4a81d0a02f Add three timeouts and align pseudocode better with existing algorithm 2017-09-11 09:12:27 +02:00
Milosevic, Zarko
9d864da353 Initial commit 2017-07-10 08:28:56 +02:00
842 changed files with 75347 additions and 31988 deletions

View File

@@ -10,6 +10,16 @@ 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:
@@ -40,6 +50,18 @@ 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
View File

@@ -17,6 +17,14 @@ 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

View File

@@ -22,7 +22,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.17"
go-version: "1.18"
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6
with:
@@ -43,7 +43,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.17"
go-version: "1.18"
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6
with:
@@ -65,7 +65,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.17"
go-version: "1.18"
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6
with:

View File

@@ -7,7 +7,7 @@ name: Check generated code
on:
pull_request:
branches:
- v0.34.x
- main
permissions:
contents: read
@@ -18,7 +18,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: '1.17'
go-version: "1.18"
- uses: actions/checkout@v3
@@ -26,8 +26,6 @@ jobs:
run: |
set -euo pipefail
readonly MOCKERY=2.12.3 # N.B. no leading "v"
curl -sL "https://github.com/vektra/mockery/releases/download/v${MOCKERY}/mockery_${MOCKERY}_Linux_x86_64.tar.gz" | tar -C /usr/local/bin -xzf -
make mockery 2>/dev/null
if ! git diff --stat --exit-code ; then
@@ -44,11 +42,11 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: '1.17'
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: |
@@ -61,7 +59,7 @@ jobs:
export GOBIN="${tools}/bin"
go install github.com/bufbuild/buf/cmd/buf
go install github.com/gogo/protobuf/protoc-gen-gogofaster@latest
go install github.com/cosmos/gogoproto/protoc-gen-gogofaster@latest
make proto-gen

View File

@@ -6,8 +6,10 @@ 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]+-rc*" # Push events to matching v*, i.e. v1.0-rc1, v20.15.10-rc5
- "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching v*, i.e. v1.0, v20.15.10
- "v[0-9]+.[0-9]+.[0-9]+-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:
build:
@@ -49,7 +51,7 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Publish to Docker Hub
uses: docker/build-push-action@v3.1.0
uses: docker/build-push-action@v3.1.1
with:
context: .
file: ./DOCKER/Dockerfile

View File

@@ -8,6 +8,7 @@ on:
push:
branches:
- main
- v0.34.x
paths:
- docs/**
- spec/**
@@ -40,7 +41,7 @@ jobs:
- uses: actions/upload-artifact@v3
with:
name: build-output
path: ~/output/
path: /tmp/tendermint-core-docs
deploy:
name: Deploy to GitHub Pages

View File

@@ -1,21 +1,20 @@
# TODO(thane): Re-enable once we've pulled in the ADRs and RFCs from master.
# Verify that important design docs have ToC entries.
#name: Check documentation ToC
#on:
# pull_request:
# push:
# branches:
# - main
#
#jobs:
# check:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v3
# - uses: technote-space/get-diff-action@v6
# with:
# PATTERNS: |
# docs/architecture/**
# docs/rfc/**
# - run: ./docs/presubmit.sh
# if: env.GIT_DIFF
name: Check documentation ToC
on:
pull_request:
push:
branches:
- main
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6
with:
PATTERNS: |
docs/architecture/**
docs/rfc/**
- run: make check-docs-toc
if: env.GIT_DIFF

View File

@@ -17,7 +17,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: '1.17'
go-version: '1.18'
- uses: actions/checkout@v3

View File

@@ -15,18 +15,24 @@ jobs:
strategy:
fail-fast: false
matrix:
group: ['00', '01', '02', '03', "04"]
group: ['00', '01']
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/setup-go@v3
with:
go-version: '1.17'
go-version: '1.18'
- uses: actions/checkout@v3
with:
ref: 'v0.34.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.
@@ -41,18 +47,33 @@ jobs:
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: rtCamp/action-slack-notify@12e36fc18b0689399306c2e0b3e0f2978b7f1ee7
uses: slackapi/slack-github-action@v1.22.0
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: tendermint-internal
SLACK_USERNAME: Nightly E2E Tests
SLACK_ICON_EMOJI: ':skull:'
SLACK_COLOR: danger
SLACK_MESSAGE: Nightly E2E tests failed on v0.34.x
SLACK_FOOTER: ''
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."
}
}
]
}

79
.github/workflows/e2e-nightly-37x.yml vendored Normal file
View File

@@ -0,0 +1,79 @@
# 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."
}
}
]
}

View File

@@ -22,7 +22,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: '1.17'
go-version: '1.18'
- uses: actions/checkout@v3
@@ -46,28 +46,23 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Notify Slack on failure
uses: rtCamp/action-slack-notify@12e36fc18b0689399306c2e0b3e0f2978b7f1ee7
uses: slackapi/slack-github-action@v1.22.0
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: tendermint-internal
SLACK_USERNAME: Nightly E2E Tests
SLACK_ICON_EMOJI: ':skull:'
SLACK_COLOR: danger
SLACK_MESSAGE: Nightly E2E tests failed on main
SLACK_FOOTER: ''
e2e-nightly-success: # may turn this off once they seem to pass consistently
needs: e2e-nightly-test
if: ${{ success() }}
runs-on: ubuntu-latest
steps:
- name: Notify Slack on success
uses: rtCamp/action-slack-notify@12e36fc18b0689399306c2e0b3e0f2978b7f1ee7
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: tendermint-internal
SLACK_USERNAME: Nightly E2E Tests
SLACK_ICON_EMOJI: ':white_check_mark:'
SLACK_COLOR: good
SLACK_MESSAGE: Nightly E2E tests passed on main
SLACK_FOOTER: ''
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
BRANCH: ${{ github.ref_name }}
RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
COMMIT_URL: "${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}"
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."
}
}
]
}

View File

@@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: '1.17'
go-version: '1.18'
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6
with:

View File

@@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: '1.17'
go-version: '1.18'
- uses: actions/checkout@v3
@@ -75,13 +75,24 @@ jobs:
if: ${{ needs.fuzz-nightly-test.outputs.crashers-count != 0 }}
runs-on: ubuntu-latest
steps:
- name: Notify Slack if any crashers
uses: rtCamp/action-slack-notify@12e36fc18b0689399306c2e0b3e0f2978b7f1ee7
- name: Notify Slack on failure
uses: slackapi/slack-github-action@v1.22.0
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: tendermint-internal
SLACK_USERNAME: Nightly Fuzz Tests
SLACK_ICON_EMOJI: ':firecracker:'
SLACK_COLOR: danger
SLACK_MESSAGE: Crashers found in Nightly Fuzz tests
SLACK_FOOTER: ''
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
BRANCH: ${{ github.ref_name }}
CRASHERS: ${{ needs.fuzz-nightly-test.outputs.crashers-count }}
RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
with:
payload: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":skull: Nightly fuzz tests for `${{ env.BRANCH }}` failed with ${{ env.CRASHERS }} crasher(s). See the <${{ env.RUN_URL }}|run details>."
}
}
]
}

41
.github/workflows/gosec.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
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

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
- uses: styfle/cancel-workflow-action@0.10.0
- uses: styfle/cancel-workflow-action@0.10.1
with:
workflow_id: 1041851,1401230,2837803
access_token: ${{ github.token }}

View File

@@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '1.17'
go-version: '1.18'
- uses: technote-space/get-diff-action@v6
with:
PATTERNS: |
@@ -34,7 +34,7 @@ jobs:
# Required: the version of golangci-lint is required and
# must be specified without patch version: we always use the
# latest patch version.
version: v1.45
version: v1.47.3
args: --timeout 10m
github-token: ${{ secrets.github_token }}
if: env.GIT_DIFF

40
.github/workflows/pre-release.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
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 }}

View File

@@ -15,7 +15,7 @@ jobs:
timeout-minutes: 5
steps:
- uses: actions/checkout@v3
- uses: bufbuild/buf-setup-action@v1.6.0
- uses: bufbuild/buf-setup-action@v1.8.0
- uses: bufbuild/buf-lint-action@v1
with:
input: 'proto'

View File

@@ -16,7 +16,7 @@ jobs:
- uses: actions/setup-go@v3
with:
go-version: '1.17'
go-version: '1.18'
- name: Build
uses: goreleaser/goreleaser-action@v3

View File

@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5
- uses: actions/stale@v6
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: "This pull request has been automatically marked as stale because it has not had

View File

@@ -18,7 +18,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.17"
go-version: "1.18"
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6
with:

3
.gitignore vendored
View File

@@ -1,5 +1,6 @@
*.bak
*.iml
*.log
*.swo
*.swp
*/.glide
@@ -37,6 +38,7 @@ terraform.tfstate
terraform.tfstate.backup
terraform.tfstate.d
test/app/grpc_client
test/loadtime/build
test/e2e/build
test/e2e/networks/*/
test/logs
@@ -50,7 +52,6 @@ proto/spec/**/*.pb.go
*.aux
*.bbl
*.blg
*.log
*.pdf
*.gz
*.dvi

View File

@@ -21,7 +21,7 @@ linters:
- nolintlint
- prealloc
- staticcheck
- structcheck
# - structcheck // to be fixed by golangci-lint
- stylecheck
- typecheck
- unconvert

View File

@@ -25,7 +25,8 @@ checksum:
algorithm: sha256
release:
name_template: "{{.Version}} (WARNING: BETA SOFTWARE)"
prerelease: auto
name_template: "{{.Version}}"
archives:
- files:

View File

@@ -8,8 +8,10 @@ default: true
MD001: false
MD007: {indent: 4}
MD013: false
MD024: { siblings_only: true }
MD024: {siblings_only: true}
MD025: false
MD033: { no-inline-html: false }
no-hard-tabs: false
whitespace: false
MD033: false
MD036: false
MD010: false
MD012: false
MD028: false

View File

@@ -2,6 +2,38 @@
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
@@ -438,7 +470,7 @@ Special thanks to external contributors on this release: @james-ray, @fedekunze,
- [abci] [\#5174](https://github.com/tendermint/tendermint/pull/5174) Remove `MockEvidence` in favor of testing with actual evidence types (`DuplicateVoteEvidence` & `LightClientAttackEvidence`) (@cmwaters)
- [abci] [\#5191](https://github.com/tendermint/tendermint/pull/5191) Add `InitChain.InitialHeight` field giving the initial block height (@erikgrinaker)
- [abci] [\#5227](https://github.com/tendermint/tendermint/pull/5227) Add `ResponseInitChain.app_hash` which is recorded in genesis block (@erikgrinaker)
- [config] [\#5147](https://github.com/tendermint/tendermint/pull/5147) Add `--consensus.double_sign_check_height` flag and `DoubleSignCheckHeight` config variable. See [ADR-51](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-051-double-signing-risk-reduction.md) (@dongsam)
- [config] [\#5147](https://github.com/tendermint/tendermint/pull/5147) Add `--consensus.double_sign_check_height` flag and `DoubleSignCheckHeight` config variable. See [ADR-51](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-051-double-signing-risk-reduction.md) (@dongsam)
- [db] [\#5233](https://github.com/tendermint/tendermint/pull/5233) Add support for `badgerdb` database backend (@erikgrinaker)
- [evidence] [\#4532](https://github.com/tendermint/tendermint/pull/4532) Handle evidence from light clients (@melekes)
- [evidence] [#4821](https://github.com/tendermint/tendermint/pull/4821) Amnesia (light client attack) evidence can be detected, verified and committed (@cmwaters)
@@ -452,7 +484,7 @@ Special thanks to external contributors on this release: @james-ray, @fedekunze,
- [rpc] [\#5017](https://github.com/tendermint/tendermint/pull/5017) Add `/check_tx` endpoint to check transactions without executing them or adding them to the mempool (@melekes)
- [rpc] [\#5108](https://github.com/tendermint/tendermint/pull/5108) Subscribe using the websocket for new evidence events (@cmwaters)
- [statesync] Add state sync support, where a new node can be rapidly bootstrapped by fetching state snapshots from peers instead of replaying blocks. See the `[statesync]` config section.
- [evidence] [\#5361](https://github.com/tendermint/tendermint/pull/5361) Add LightClientAttackEvidence and refactor evidence lifecycle - for more information see [ADR-059](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-059-evidence-composition-and-lifecycle.md) (@cmwaters)
- [evidence] [\#5361](https://github.com/tendermint/tendermint/pull/5361) Add LightClientAttackEvidence and refactor evidence lifecycle - for more information see [ADR-059](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-059-evidence-composition-and-lifecycle.md) (@cmwaters)
### IMPROVEMENTS
@@ -532,7 +564,7 @@ This security release fixes:
Tendermint 0.33.0 and above allow block proposers to include signatures for the
wrong block. This may happen naturally if you start a network, have it run for
some time and restart it **without changing the chainID**. (It is a
[misconfiguration](https://docs.tendermint.com/master/tendermint-core/using-tendermint.html)
[misconfiguration](https://docs.tendermint.com/v0.33/tendermint-core/using-tendermint.html)
to reuse chainIDs.) Correct block proposers will accidentally include signatures
for the wrong block if they see these signatures, and then commits won't validate,
making all proposed blocks invalid. A malicious validator (even with a minimal
@@ -831,7 +863,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/spec/blob/master/spec/consensus/light-client.md) for complete details.
subjectivity interface. Refer to the [spec](https://github.com/tendermint/tendermint/tree/main/spec/consensus/light-client) for complete details.
`lite` package is now deprecated and will be removed in v0.34 release.
### BREAKING CHANGES:
@@ -1191,8 +1223,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://github.com/tendermint/tendermint/blob/master/docs/guides/java.md)
@climber73 wrote the [Writing a Tendermint Core application in Java
(gRPC)](https://docs.tendermint.com/v0.34/tutorials/java.html)
guide.
Special thanks to external contributors on this release:
@@ -1225,7 +1257,7 @@ Special thanks to external contributors on this release:
### FEATURES:
- [blockchain] [\#3561](https://github.com/tendermint/tendermint/issues/3561) Add early version of the new blockchain reactor, which is supposed to be more modular and testable compared to the old version. To try it, you'll have to change `version` in the config file, [here](https://github.com/tendermint/tendermint/blob/master/config/toml.go#L303) NOTE: It's not ready for a production yet. For further information, see [ADR-40](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-040-blockchain-reactor-refactor.md) & [ADR-43](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-043-blockchain-riri-org.md)
- [blockchain] [\#3561](https://github.com/tendermint/tendermint/issues/3561) Add early version of the new blockchain reactor, which is supposed to be more modular and testable compared to the old version. To try it, you'll have to change `version` in the config file, [here](https://github.com/tendermint/tendermint/blob/main/config/toml.go#L303) NOTE: It's not ready for a production yet. For further information, see [ADR-40](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-040-blockchain-reactor-refactor.md) & [ADR-43](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-043-blockchain-riri-org.md)
- [mempool] [\#3826](https://github.com/tendermint/tendermint/issues/3826) Make `max_msg_bytes` configurable(@bluele)
- [node] [\#3846](https://github.com/tendermint/tendermint/pull/3846) Allow replacing existing p2p.Reactor(s) using [`CustomReactors`
option](https://godoc.org/github.com/tendermint/tendermint/node#CustomReactors).
@@ -1283,7 +1315,7 @@ This release contains a minor enhancement to the ABCI and some breaking changes
- [p2p] [\#3338](https://github.com/tendermint/tendermint/issues/3338) Prevent "sent next PEX request too soon" errors by not calling
ensurePeers outside of ensurePeersRoutine
- [behaviour] [\3772](https://github.com/tendermint/tendermint/pull/3772) Return correct reason in MessageOutOfOrder (@jim380)
- [behavior] [\3772](https://github.com/tendermint/tendermint/pull/3772) Return correct reason in MessageOutOfOrder (@jim380)
- [config] [\#3723](https://github.com/tendermint/tendermint/issues/3723) Add consensus_params to testnet config generation; document time_iota_ms (@ashleyvega)
@@ -1542,7 +1574,7 @@ Special thanks to external contributors on this release:
- [libs/db] [\#3611](https://github.com/tendermint/tendermint/issues/3611) Conditional compilation
* Use `cleveldb` tag instead of `gcc` to compile Tendermint with CLevelDB or
use `make build_c` / `make install_c` (full instructions can be found at
https://docs.tendermint.com/master/introduction/install.html#compile-with-cleveldb-support)
<https://docs.tendermint.com>)
* Use `boltdb` tag to compile Tendermint with bolt db
- [node] [\#3362](https://github.com/tendermint/tendermint/issues/3362) Return an error if `persistent_peers` list is invalid (except
when IP lookup fails)
@@ -1603,7 +1635,7 @@ It brings back `NetAddress()` to `NodeInfo` and uses it instead of `SocketAddr`
Additionally, it improves response time on the `/validators` or `/status` RPC endpoints.
As a side-effect it makes these RPC endpoint more difficult to DoS and fixes a performance degradation in `ExecCommitBlock`.
Also, it contains an [ADR](https://github.com/tendermint/tendermint/pull/3539) that proposes decoupling the
responsibility for peer behaviour from the `p2p.Switch` (by @brapse).
responsibility for peer behavior from the `p2p.Switch` (by @brapse).
Special thanks to external contributors on this release:
@brapse, @guagualvcha, @mydring
@@ -1766,7 +1798,7 @@ more details.
- [rpc] [\#3269](https://github.com/tendermint/tendermint/issues/2826) Limit number of unique clientIDs with open subscriptions. Configurable via `rpc.max_subscription_clients`
- [rpc] [\#3269](https://github.com/tendermint/tendermint/issues/2826) Limit number of unique queries a given client can subscribe to at once. Configurable via `rpc.max_subscriptions_per_client`.
- [rpc] [\#3435](https://github.com/tendermint/tendermint/issues/3435) Default ReadTimeout and WriteTimeout changed to 10s. WriteTimeout can increased by setting `rpc.timeout_broadcast_tx_commit` in the config.
- [rpc/client] [\#3269](https://github.com/tendermint/tendermint/issues/3269) Update `EventsClient` interface to reflect new pubsub/eventBus API [ADR-33](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-033-pubsub.md). This includes `Subscribe`, `Unsubscribe`, and `UnsubscribeAll` methods.
- [rpc/client] [\#3269](https://github.com/tendermint/tendermint/issues/3269) Update `EventsClient` interface to reflect new pubsub/eventBus API [ADR-33](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-033-pubsub.md). This includes `Subscribe`, `Unsubscribe`, and `UnsubscribeAll` methods.
* Apps
- [abci] [\#3403](https://github.com/tendermint/tendermint/issues/3403) Remove `time_iota_ms` from BlockParams. This is a
@@ -1819,7 +1851,7 @@ more details.
- [blockchain] [\#3358](https://github.com/tendermint/tendermint/pull/3358) Fix timer leak in `BlockPool` (@guagualvcha)
- [cmd] [\#3408](https://github.com/tendermint/tendermint/issues/3408) Fix `testnet` command's panic when creating non-validator configs (using `--n` flag) (@srmo)
- [libs/db/remotedb/grpcdb] [\#3402](https://github.com/tendermint/tendermint/issues/3402) Close Iterator/ReverseIterator after use
- [libs/pubsub] [\#951](https://github.com/tendermint/tendermint/issues/951), [\#1880](https://github.com/tendermint/tendermint/issues/1880) Use non-blocking send when dispatching messages [ADR-33](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-033-pubsub.md)
- [libs/pubsub] [\#951](https://github.com/tendermint/tendermint/issues/951), [\#1880](https://github.com/tendermint/tendermint/issues/1880) Use non-blocking send when dispatching messages [ADR-33](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-033-pubsub.md)
- [lite] [\#3364](https://github.com/tendermint/tendermint/issues/3364) Fix `/validators` and `/abci_query` proxy endpoints
(@guagualvcha)
- [p2p/conn] [\#3347](https://github.com/tendermint/tendermint/issues/3347) Reject all-zero shared secrets in the Diffie-Hellman step of secret-connection
@@ -2271,8 +2303,8 @@ Special thanks to external contributors on this release:
- [blockchain] [\#2731](https://github.com/tendermint/tendermint/issues/2731) Retry both blocks if either is bad to avoid getting stuck during fast sync (@goolAdapter)
- [consensus] [\#2893](https://github.com/tendermint/tendermint/issues/2893) Use genDoc.Validators instead of state.NextValidators on replay when appHeight==0 (@james-ray)
- [log] [\#2868](https://github.com/tendermint/tendermint/issues/2868) Fix `module=main` setting overriding all others
- NOTE: this changes the default logging behaviour to be much less verbose.
Set `log_level="info"` to restore the previous behaviour.
- NOTE: this changes the default logging behavior to be much less verbose.
Set `log_level="info"` to restore the previous behavior.
- [rpc] [\#2808](https://github.com/tendermint/tendermint/issues/2808) Fix `accum` field in `/validators` by calling `IncrementAccum` if necessary
- [rpc] [\#2811](https://github.com/tendermint/tendermint/issues/2811) Allow integer IDs in JSON-RPC requests (@tomtau)
- [txindex/kv] [\#2759](https://github.com/tendermint/tendermint/issues/2759) Fix tx.height range queries
@@ -2403,7 +2435,7 @@ increasing attention to backwards compatibility. Thanks for bearing with us!
* [state] [\#2644](https://github.com/tendermint/tendermint/issues/2644) Add Version field to State, breaking the format of State as
encoded on disk.
* [rpc] [\#2298](https://github.com/tendermint/tendermint/issues/2298) `/abci_query` takes `prove` argument instead of `trusted` and switches the default
behaviour to `prove=false`
behavior to `prove=false`
* [rpc] [\#2654](https://github.com/tendermint/tendermint/issues/2654) Remove all `node_info.other.*_version` fields in `/status` and
`/net_info`
* [rpc] [\#2636](https://github.com/tendermint/tendermint/issues/2636) Remove
@@ -2517,7 +2549,7 @@ Special thanks to external contributors on this release:
This release is mostly about the ConsensusParams - removing fields and enforcing MaxGas.
It also addresses some issues found via security audit, removes various unused
functions from `libs/common`, and implements
[ADR-012](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-012-peer-transport.md).
[ADR-012](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-012-peer-transport.md).
BREAKING CHANGES:
@@ -2548,7 +2580,7 @@ FEATURES:
- [libs] [\#2286](https://github.com/tendermint/tendermint/issues/2286) Panic if `autofile` or `db/fsdb` permissions change from 0600.
IMPROVEMENTS:
- [libs/db] [\#2371](https://github.com/tendermint/tendermint/issues/2371) Output error instead of panic when the given `db_backend` is not initialised (@bradyjoestar)
- [libs/db] [\#2371](https://github.com/tendermint/tendermint/issues/2371) Output error instead of panic when the given `db_backend` is not initialized (@bradyjoestar)
- [mempool] [\#2399](https://github.com/tendermint/tendermint/issues/2399) Make mempool cache a proper LRU (@bradyjoestar)
- [p2p] [\#2126](https://github.com/tendermint/tendermint/issues/2126) Introduce PeerTransport interface to improve isolation of concerns
- [libs/common] [\#2326](https://github.com/tendermint/tendermint/issues/2326) Service returns ErrNotStarted
@@ -2582,7 +2614,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/develop/docs/architecture)
[here](https://github.com/tendermint/tendermint/tree/main/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).
@@ -2598,7 +2630,7 @@ BREAKING CHANGES:
- [abci] Added address of the original proposer of the block to Header
- [abci] Change ABCI Header to match Tendermint exactly
- [abci] [\#2159](https://github.com/tendermint/tendermint/issues/2159) Update use of `Validator` (see
[ADR-018](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-018-ABCI-Validators.md)):
[ADR-018](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-018-ABCI-Validators.md)):
- Remove PubKey from `Validator` (so it's just Address and Power)
- Introduce `ValidatorUpdate` (with just PubKey and Power)
- InitChain and EndBlock use ValidatorUpdate
@@ -2620,7 +2652,7 @@ BREAKING CHANGES:
- [state] [\#1815](https://github.com/tendermint/tendermint/issues/1815) Validator set changes are now delayed by one block (!)
- Add NextValidatorSet to State, changes on-disk representation of state
- [state] [\#2184](https://github.com/tendermint/tendermint/issues/2184) Enforce ConsensusParams.BlockSize.MaxBytes (See
[ADR-020](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-020-block-size.md)).
[ADR-020](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-020-block-size.md)).
- Remove ConsensusParams.BlockSize.MaxTxs
- Introduce maximum sizes for all components of a block, including ChainID
- [types] Updates to the block Header:
@@ -2631,7 +2663,7 @@ BREAKING CHANGES:
- [consensus] [\#2203](https://github.com/tendermint/tendermint/issues/2203) Implement BFT time
- Timestamp in block must be monotonic and equal the median of timestamps in block's LastCommit
- [crypto] [\#2239](https://github.com/tendermint/tendermint/issues/2239) Secp256k1 signature changes (See
[ADR-014](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-014-secp-malleability.md)):
[ADR-014](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-014-secp-malleability.md)):
- format changed from DER to `r || s`, both little endian encoded as 32 bytes.
- malleability removed by requiring `s` to be in canonical form.
@@ -2861,7 +2893,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://tendermint.readthedocs.io/projects/tools/en/develop/metrics.html)
[metrics](https://github.com/tendermint/tendermint/blob/main/docs/tendermint-core/metrics.md)
guide.
- [p2p] Add IPv6 support to peering.
- [p2p] Add `external_address` to config to allow specifying the address for
@@ -2975,7 +3007,7 @@ BREAKING:
FEATURES
- [rpc] the RPC documentation is now published to https://tendermint.github.io/slate
- [rpc] the RPC documentation is now published to https://github.com/tendermint/tendermint/tree/main/spec/rpc
- [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
@@ -3431,7 +3463,7 @@ Also includes the Grand Repo-Merge of 2017.
BREAKING CHANGES:
- Config and Flags:
- The `config` map is replaced with a [`Config` struct](https://github.com/tendermint/tendermint/blob/master/config/config.go#L11),
- The `config` map is replaced with a [`Config` struct](https://github.com/tendermint/tendermint/blob/main/config/config.go#L11),
containing substructs: `BaseConfig`, `P2PConfig`, `MempoolConfig`, `ConsensusConfig`, `RPCConfig`
- This affects the following flags:
- `--seeds` is now `--p2p.seeds`
@@ -3454,7 +3486,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/tmlibs/log) and [blog post](https://tendermint.com/blog/abstracting-the-logger-interface-in-go) for more details
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
- 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

View File

@@ -1,10 +1,6 @@
# Unreleased Changes
## v0.34.21
Special thanks to external contributors on this release:
Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint).
## v0.38.0
### BREAKING CHANGES
@@ -18,10 +14,84 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
- Blockchain Protocol
### FEATURES
- 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)
- [#9083] backport cli command to reindex missed events (@cmwaters)
### 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:
Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint).
### BREAKING CHANGES
- CLI/RPC/Config
- [config] \#9259 Rename the fastsync section and the fast_sync key blocksync and block_sync respectively
- Apps
- [abci/counter] \#6684 Delete counter example app
- [abci] \#5783 Make length delimiter encoding consistent (`uint64`) between ABCI and P2P wire-level protocols
- [abci] \#9145 Removes unused Response/Request `SetOption` from ABCI (@samricotta)
- [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)
- P2P Protocol
- 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
### FEATURES
- [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.
### BUG FIXES
- [consensus] \#9229 fix round number of `enterPropose` when handling `RoundStepNewRound` timeout. (@fatcat22)
- [docker] \#9073 enable cross platform build using docker buildx

View File

@@ -1,59 +1,109 @@
# The Tendermint Code of Conduct
This code of conduct applies to all projects run by the Tendermint/COSMOS team and hence to tendermint.
This code of conduct applies to all projects run by the Tendermint/COSMOS team
and hence to Tendermint.
----
# Conduct
## Contact: conduct@tendermint.com
* 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 characteristic.
* 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 characteristic.
* On Slack, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
* On Slack, please avoid using overtly sexual nicknames or other nicknames that
might detract from a friendly, safe and welcoming environment for all.
* Please be kind and courteous. Theres no need to be mean or rude.
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
* Respect that people have differences of opinion and that every design or
implementation choice carries a trade-off and numerous costs. There is seldom
a right answer.
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
* Please keep unstructured critique to a minimum. If you have solid ideas you
want to experiment with, make a fork and see how it works.
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we dont tolerate behavior that excludes people in socially marginalized groups.
* We will exclude you from interaction if you insult, demean or harass anyone.
That is not welcome behavior. We interpret the term “harassment” as including
the definition in the [Citizen Code of Conduct][ccoc]; if you have any lack of
clarity about what might be included in that concept, please read their
definition. In particular, we dont tolerate behavior that excludes people in
socially marginalized groups.
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel admins or the person mentioned above immediately. Whether youre a regular contributor or a newcomer, we care about making this community a safe place for you and weve got your back.
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome.
* Private harassment is also unacceptable. No matter who you are, if you feel
you have been or are being harassed or made uncomfortable by a community
member, please contact one of the channel admins or the person mentioned above
immediately. Whether youre a regular contributor or a newcomer, we care about
making this community a safe place for you and weve got your back.
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing
behavior is not welcome.
----
# Moderation
These are the policies for upholding our communitys standards of conduct. If you feel that a thread needs moderation, please contact the above mentioned person.
These are the policies for upholding our communitys standards of conduct. If
you feel that a thread needs moderation, please contact the above mentioned
person.
1. Remarks that violate the Tendermint/COSMOS standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
1. Remarks that violate the Tendermint/COSMOS standards of conduct, including
hateful, hurtful, oppressive, or exclusionary remarks, are not allowed.
(Cursing is allowed, but never targeting another user, and never in a hateful
manner.)
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
2. Remarks that moderators find inappropriate, whether listed in the code of
conduct or not, are also not allowed.
3. Moderators will first respond to such remarks with a warning.
4. If the warning is unheeded, the user will be “kicked,” i.e., kicked out of the communication channel to cool off.
4. If the warning is unheeded, the user will be “kicked,” i.e., kicked out of
the communication channel to cool off.
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
5. If the user comes back and continues to make trouble, they will be banned,
i.e., indefinitely excluded.
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
6. Moderators may choose at their discretion to un-ban the user if it was a
first offense and they offer the offended party a genuine apology.
7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, in private. Complaints about bans in-channel are not allowed.
7. If a moderator bans someone and you think it was unjustified, please take it
up with that moderator, or with a different moderator, in private. Complaints
about bans in-channel are not allowed.
8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
8. Moderators are held to a higher standard than other community members. If a
moderator creates an inappropriate situation, they should expect less leeway
than others.
In the Tendermint/COSMOS community we strive to go the extra step to look out for each other. Dont just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if theyre off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
In the Tendermint/COSMOS community we strive to go the extra step to look out
for each other. Dont just aim to be technically unimpeachable, try to be your
best self. In particular, avoid flirting with offensive or sensitive issues,
particularly if theyre off-topic; this all too often leads to unnecessary
fights, hurt feelings, and damaged trust; worse, it can drive people away
from the community entirely.
And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you couldve communicated better — remember that its your responsibility to make your fellow Cosmonauts comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
And if someone takes issue with something you said or did, resist the urge to be
defensive. Just stop doing what it was they complained about and apologize. Even
if you feel you were misinterpreted or unfairly accused, chances are good there
was something you couldve communicated better — remember that its your
responsibility to make your fellow Cosmonauts comfortable. Everyone wants to
get along and we are all here first and foremost because we want to talk
about cool technology. You will find that people will be eager to assume
good intent and forgive as long as you earn their trust.
The enforcement policies listed above apply to all official Tendermint/COSMOS venues.For other projects adopting the Tendermint/COSMOS Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.
The enforcement policies listed above apply to all official Tendermint/COSMOS
venues. For other projects adopting the Tendermint/COSMOS Code of Conduct,
please contact the maintainers of those projects for enforcement. If you wish to
use this code of conduct for your own project, consider explicitly mentioning
your moderation policy or making a copy with your own moderation policy so as to
avoid confusion.
*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling), the [Contributor Covenant v1.3.0](http://contributor-covenant.org/version/1/3/0/) and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
\*Adapted from the [Node.js Policy on Trolling][node-trolling-policy], the
[Contributor Covenant v1.3.0][ccov] and the [Rust Code of Conduct][rust-coc].
[ccoc]: https://github.com/stumpsyn/policies/blob/master/citizen_code_of_conduct.md
[node-trolling-policy]: http://blog.izs.me/post/30036893703/policy-on-trolling
[ccov]: http://contributor-covenant.org/version/1/3/0/
[rust-coc]: https://www.rust-lang.org/en-US/conduct.html

View File

@@ -7,7 +7,7 @@ support permissionless value-carrying networks. While all contributions are
welcome, contributors should bear this goal in mind in deciding if they should
target the main Tendermint project or a potential fork. When targeting the
main Tendermint project, the following process leads to the best chance of
landing changes in master.
landing changes in `main`.
All work on the code base should be motivated by a [Github
Issue](https://github.com/tendermint/tendermint/issues).
@@ -26,7 +26,8 @@ will indicate their support with a heartfelt emoji.
If the issue would benefit from thorough discussion, maintainers may
request that you create a [Request For
Comment](https://github.com/tendermint/spec/tree/master/rfc). Discussion
Comment](https://github.com/tendermint/tendermint/tree/main/docs/rfc)
in the Tendermint spec repo. Discussion
at the RFC stage will build collective understanding of the dimensions
of the problems and help structure conversations around trade-offs.
@@ -45,7 +46,7 @@ Find the largest existing ADR number and bump it by 1.
When the problem as well as proposed solution are well understood,
changes should start with a [draft
pull request](https://github.blog/2019-02-14-introducing-draft-pull-requests/)
against master. The draft signals that work is underway. When the work
against `main`. The draft signals that work is underway. When the work
is ready for feedback, hitting "Ready for Review" will signal to the
maintainers to take a look.
@@ -53,7 +54,7 @@ maintainers to take a look.
Each stage of the process is aimed at creating feedback cycles which align contributors and maintainers to make sure:
- Contributors dont waste their time implementing/proposing features which wont land in master.
- Contributors dont waste their time implementing/proposing features which wont land in `main`.
- Maintainers have the necessary context in order to support and review contributions.
## Forking
@@ -72,19 +73,19 @@ For instance, to create a fork and work on a branch of it, I would:
- `git remote add origin git@github.com:ebuchman/basecoin.git`
Now `origin` refers to my fork and `upstream` refers to the Tendermint version.
So I can `git push -u origin master` to update my fork, and make pull requests to tendermint from there.
So I can `git push -u origin main` to update my fork, and make pull requests to tendermint from there.
Of course, replace `ebuchman` with your git handle.
To pull in updates from the origin repo, run
- `git fetch upstream`
- `git rebase upstream/master` (or whatever branch you want)
- `git rebase upstream/main` (or whatever branch you want)
## Dependencies
We use [go modules](https://github.com/golang/go/wiki/Modules) to manage dependencies.
That said, the master branch of every Tendermint repository should just build
That said, the `main` branch of every Tendermint repository should just build
with `go get`, which means they should be kept up-to-date with their
dependencies so we can get away with telling people they can just `go get` our
software.
@@ -104,24 +105,46 @@ 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/gogo/protobuf) to generate code for use across Tendermint Core.
We use [Protocol Buffers](https://developers.google.com/protocol-buffers) along
with [`gogoproto`](https://github.com/cosmos/gogoproto) to generate code for use
across Tendermint Core.
For linting and checking breaking changes, we use [buf](https://buf.build/). If you would like to run linting and check if the changes you have made are breaking then you will need to have docker running locally. Then the linting cmd will be `make proto-lint` and the breaking changes check will be `make proto-check-breaking`.
To generate proto stubs, lint, and check protos for breaking changes, you will
need to install [buf](https://buf.build/) and `gogoproto`. Then, from the root
of the repository, run:
We use [Docker](https://www.docker.com/) to generate the protobuf stubs. To generate the stubs yourself, make sure docker is running then run `make proto-gen`.
```bash
# Lint all of the .proto files in proto/tendermint
make proto-lint
## Vagrant
# Check if any of your local changes (prior to committing to the Git repository)
# are breaking
make proto-check-breaking
If you are a [Vagrant](https://www.vagrantup.com/) user, you can get started
hacking Tendermint with the commands below.
# Generate Go code from the .proto files in proto/tendermint
make proto-gen
```
NOTE: In case you installed Vagrant in 2017, you might need to run
`vagrant box update` to upgrade to the latest `ubuntu/xenial64`.
To automatically format `.proto` files, you will need
[`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) installed. Once
installed, you can run:
```sh
vagrant up
vagrant ssh
make test
```bash
make proto-format
```
### Visual Studio Code
If you are a VS Code user, you may want to add the following to your `.vscode/settings.json`:
```json
{
"protoc": {
"options": [
"--proto_path=${workspaceRoot}/proto",
]
}
}
```
## Changelog
@@ -129,10 +152,47 @@ make test
Every fix, improvement, feature, or breaking change should be made in a
pull-request that includes an update to the `CHANGELOG_PENDING.md` file.
A feature can also be worked on a feature branch, if its size and/or risk
justifies it (see #branching-model-and-release) below.
### What does a good changelog entry look like?
Changelog entries should answer the question: "what is important about this
change for users to know?" or "what problem does this solve for users?". It
should not simply be a reiteration of the title of the associated PR, unless the
title of the PR _very_ clearly explains the benefit of a change to a user.
Some good examples of changelog entry descriptions:
```md
- [consensus] \#1111 Small transaction throughput improvement (approximately
3-5\% from preliminary tests) through refactoring the way we use channels
- [mempool] \#1112 Refactor Go API to be able to easily swap out the current
mempool implementation in Tendermint forks
- [p2p] \#1113 Automatically ban peers when their messages are unsolicited or
are received too frequently
```
Some bad examples of changelog entry descriptions:
```md
- [consensus] \#1111 Refactor channel usage
- [mempool] \#1112 Make API generic
- [p2p] \#1113 Ban for PEX message abuse
```
For more on how to write good changelog entries, see:
- <https://keepachangelog.com>
- <https://docs.gitlab.com/ee/development/changelog.html#writing-good-changelog-entries>
- <https://depfu.com/blog/what-makes-a-good-changelog>
### Changelog entry format
Changelog entries should be formatted as follows:
```md
- [module] \#xxx Some description about the change (@contributor)
- [module] \#xxx Some description of the change (@contributor)
```
Here, `module` is the part of the code that changed (typically a
@@ -160,22 +220,31 @@ removed from the header in RPC responses as well.
## Branching Model and Release
The main development branch is master.
The main development branch is `main`.
Every release is maintained in a release branch named `vX.Y.Z`.
Pending minor releases have long-lived release candidate ("RC") branches. Minor release changes should be merged to these long-lived RC branches at the same time that the changes are merged to master.
Pending minor releases have long-lived release candidate ("RC") branches. Minor release changes should be merged to these long-lived RC branches at the same time that the changes are merged to `main`.
If a feature's size is big and/or its risk is high, it can be implemented in a feature branch.
While the feature work is in progress,
pull requests are open and squash merged against the feature branch.
Branch `main` is periodically merged (merge commit) into the feature branch,
to reduce branch divergence.
When the feature is complete, the feature branch is merged back (merge commit) into `main`.
The moment of the final merge can be carefully chosen
so as to land different features in different releases.
Note all pull requests should be squash merged except for merging to a release branch (named `vX.Y`). This keeps the commit history clean and makes it
easy to reference the pull request where a change was introduced.
### Development Procedure
The latest state of development is on `master`, which must never fail `make test`. _Never_ force push `master`, unless fixing broken git history (which we rarely do anyways).
The latest state of development is on `main`, which must never fail `make test`. _Never_ force push `main`, unless fixing broken git history (which we rarely do anyways).
To begin contributing, create a development branch either on `github.com/tendermint/tendermint`, or your fork (using `git remote add origin`).
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 `master`. (Since pull requests are squash-merged, either is fine!)
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 it's
@@ -183,7 +252,7 @@ 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.
Sometimes (often!) pull requests get out-of-date with master, as other people merge different pull requests to master. It is our convention that pull request authors are responsible for updating their branches with master. (This also means that you shouldn't update someone else's branch for them; even if it seems like you're doing them a favor, you may be interfering with their git flow in some way!)
Sometimes (often!) pull requests get out-of-date with `main`, as other people merge different pull requests to `main`. It is our convention that pull request authors are responsible for updating their branches with `main`. (This also means that you shouldn't update someone else's branch for them; even if it seems like you're doing them a favor, you may be interfering with their git flow in some way!)
#### Merging Pull Requests
@@ -191,20 +260,20 @@ It is also our convention that authors merge their own pull requests, when possi
Before merging a pull request:
- Ensure pull branch is up-to-date with a recent `master` (GitHub won't let you merge without this!)
- Ensure pull branch is up-to-date with a recent `main` (GitHub won't let you merge without this!)
- Run `make test` to ensure that all tests pass
- [Squash](https://stackoverflow.com/questions/5189560/squash-my-last-x-commits-together-using-git) merge pull request
#### Pull Requests for Minor Releases
If your change should be included in a minor release, please also open a PR against the long-lived minor release candidate branch (e.g., `rc1/v0.33.5`) _immediately after your change has been merged to master_.
If your change should be included in a minor release, please also open a PR against the long-lived minor release candidate branch (e.g., `rc1/v0.33.5`) _immediately after your change has been merged to main_.
You can do this by cherry-picking your commit off master:
You can do this by cherry-picking your commit off `main`:
```sh
$ git checkout rc1/v0.33.5
$ git checkout -b {new branch name}
$ git cherry-pick {commit SHA from master}
$ git cherry-pick {commit SHA from main}
# may need to fix conflicts, and then use git add and git cherry-pick --continue
$ git push origin {new branch name}
```
@@ -223,90 +292,7 @@ cmd/debug: execute p.Signal only when p is not nil
Fixes #nnnn
```
Each PR should have one commit once it lands on `master`; this can be accomplished by using the "squash and merge" button on Github. Be sure to edit your commit message, though!
### Release Procedure
#### Major Release
1. Start on `master`
2. Run integration tests (see `test_integrations` in Makefile)
3. Prepare release in a pull request against `master` (to be squash merged):
- Copy `CHANGELOG_PENDING.md` to top of `CHANGELOG.md`; if this release
had release candidates, squash all the RC updates into one
- Run `python ./scripts/linkify_changelog.py CHANGELOG.md` to add links for
all issues
- run `bash ./scripts/authors.sh` to get a list of authors since the latest
release, and add the github aliases of external contributors to the top of
the changelog. To lookup an alias from an email, try `bash ./scripts/authors.sh <email>`
- Reset the `CHANGELOG_PENDING.md`
- Bump TMVersionDefault version in `version.go`
- Bump P2P and block protocol versions in `version.go`, if necessary
- Bump ABCI protocol version in `version.go`, if necessary
- Make sure all significant breaking changes are covered in `UPGRADING.md`
- Add any release notes you would like to be added to the body of the release to `release_notes.md`.
4. Push a tag with prepared release details (this will trigger the release `vX.X.0`)
- `git tag -a vX.X.x -m 'Release vX.X.x'`
- `git push origin vX.X.x`
5. Update the changelog.md file on master with the releases changelog.
6. Delete any RC branches and tags for this release (if applicable)
#### Minor Release
Minor releases are done differently from major releases: They are built off of long-lived release candidate branches, rather than from master.
1. Checkout the long-lived release candidate branch: `git checkout rcX/vX.X.X`
2. Run integration tests: `make test_integrations`
3. Prepare the release:
- copy `CHANGELOG_PENDING.md` to top of `CHANGELOG.md`
- run `python ./scripts/linkify_changelog.py CHANGELOG.md` to add links for all issues
- run `bash ./scripts/authors.sh` to get a list of authors since the latest release, and add the GitHub aliases of external contributors to the top of the CHANGELOG. To lookup an alias from an email, try `bash ./scripts/authors.sh <email>`
- reset the `CHANGELOG_PENDING.md`
- bump P2P and block protocol versions in `version.go`, if necessary
- bump ABCI protocol version in `version.go`, if necessary
- make sure all significant breaking changes are covered in `UPGRADING.md`
- Add any release notes you would like to be added to the body of the release to `release_notes.md`.
4. Create a release branch `release/vX.X.x` off the release candidate branch:
- `git checkout -b release/vX.X.x`
- `git push -u origin release/vX.X.x`
- Note that all branches prefixed with `release` are protected once pushed. You will need admin help to make any changes to the branch.
5. Once the release branch has been approved, make sure to pull it locally, then push a tag.
- `git tag -a vX.X.x -m 'Release vX.X.x'`
- `git push origin vX.X.x`
6. Create a pull request back to master with the CHANGELOG & version changes from the latest release.
- Remove all `R:minor` labels from the pull requests that were included in the release.
- Do not merge the release branch into master.
7. Delete the former long lived release candidate branch once the release has been made.
8. Create a new release candidate branch to be used for the next release.
#### Backport Release
1. start from the existing release branch you want to backport changes to (e.g. v0.30)
Branch to a release/vX.X.X branch locally (e.g. release/v0.30.7)
2. Cherry pick the commit(s) that contain the changes you want to backport (usually these commits are from squash-merged PRs which were already reviewed)
3. Follow steps 2 and 3 from [Major Release](#major-release)
4. Push changes to release/vX.X.X branch
5. Open a PR against the existing vX.X branch
#### Release Candidates
Before creating an official release, especially a major release, we may want to 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 RC branches. RC branches typically have names formatted
like `RCX/vX.X.X` (or, concretely, `RC0/v0.34.0`), while the tags themselves follow
the "standard" release naming conventions, with `-rcX` at the end (`vX.X.X-rcX`).
(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.)
1. Start from the RC branch (e.g. `RC0/v0.34.0`).
2. Create the new tag, specifying a name and a tag "message":
`git tag -a v0.34.0-rc0 -m "Release Candidate v0.34.0-rc0`
3. Push the tag back up to origin:
`git push origin v0.34.0-rc4`
Now the tag should be available on the repo's releases page.
4. Create a new release candidate branch for any possible updates to the RC:
`git checkout -b RC1/v0.34.0; git push origin RC1/v0.34.0`
Each PR should have one commit once it lands on `main`; this can be accomplished by using the "squash and merge" button on Github. Be sure to edit your commit message, though!
## Testing
@@ -340,15 +326,6 @@ cd test/e2e && \
./build/runner -f networks/ci.toml
```
### Maverick
**If you're changing the code in `consensus` package, please make sure to
replicate all the changes in `./test/maverick/consensus`**. Maverick is a
byzantine node used to assert that the validator gets punished for malicious
behavior.
See [README](./test/maverick/README.md) for details.
### Model-based tests (ADVANCED)
*NOTE: if you're just submitting your first PR, you won't need to touch these
@@ -393,8 +370,10 @@ information.
### RPC Testing
If you contribute to the RPC endpoints it's important to document your changes in the [Openapi file](./rpc/openapi/openapi.yaml)
To test your changes you should install `nodejs` and run:
**If you contribute to the RPC endpoints it's important to document your
changes in the [Openapi file](./rpc/openapi/openapi.yaml)**.
To test your changes you must install `nodejs` and run:
```bash
npm i -g dredd

View File

@@ -1,14 +1,18 @@
# 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 golang:1.15-alpine as builder
FROM --platform=$BUILDPLATFORM $GOLANG_BASE_IMAGE as builder
RUN apk update && \
apk upgrade && \
apk --no-cache add make
COPY / /tendermint
WORKDIR /tendermint
RUN make build-linux
RUN TARGETPLATFORM=$TARGETPLATFORM make build-linux
# stage 2
FROM golang:1.15-alpine
FROM $GOLANG_BASE_IMAGE
LABEL maintainer="hello@tendermint.com"
# Tendermint will be looking for the genesis file in /tendermint/config/genesis.json

View File

@@ -6,9 +6,9 @@ DockerHub tags for official releases are [here](https://hub.docker.com/r/tenderm
Official releases can be found [here](https://github.com/tendermint/tendermint/releases).
The Dockerfile for tendermint is not expected to change in the near future. The master file used for all builds can be found [here](https://raw.githubusercontent.com/tendermint/tendermint/master/DOCKER/Dockerfile).
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 <https://raw.githubusercontent.com/tendermint/tendermint/vX.XX.XX/DOCKER/Dockerfile> (replace the Xs with the version number).
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).
## Quick reference
@@ -20,9 +20,9 @@ Respective versioned files can be found <https://raw.githubusercontent.com/tende
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/master/introduction/#quick-start).
For more background, see the [the docs](https://docs.tendermint.com/main/introduction/#quick-start).
To get started developing applications, see the [application developers guide](https://docs.tendermint.com/master/introduction/quick-start.html).
To get started developing applications, see the [application developers guide](https://docs.tendermint.com/main/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/master/Makefile) and run:
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:
```sh
make build-linux
@@ -49,8 +49,8 @@ Note that this will build and use a different image than the ones provided here.
## License
- Tendermint's license is [Apache 2.0](https://github.com/tendermint/tendermint/blob/master/LICENSE).
- Tendermint's license is [Apache 2.0](https://github.com/tendermint/tendermint/blob/main/LICENSE).
## Contributing
Contributions are most welcome! See the [contributing file](https://github.com/tendermint/tendermint/blob/master/CONTRIBUTING.md) for more information.
Contributions are most welcome! See the [contributing file](https://github.com/tendermint/tendermint/blob/main/CONTRIBUTING.md) for more information.

View File

@@ -1,5 +1,3 @@
Tendermint Core
License: Apache2.0
Apache License
Version 2.0, January 2004
@@ -181,7 +179,7 @@ License: Apache2.0
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
@@ -189,7 +187,7 @@ License: Apache2.0
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2016 All in Bits, Inc
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

114
Makefile
View File

@@ -53,6 +53,67 @@ endif
# allow users to pass additional flags via the conventional LDFLAGS variable
LD_FLAGS += $(LDFLAGS)
# Process Docker environment varible TARGETPLATFORM
# in order to build binary with correspondent ARCH
# by default will always build for linux/amd64
TARGETPLATFORM ?=
GOOS ?= linux
GOARCH ?= amd64
GOARM ?=
ifeq (linux/arm,$(findstring linux/arm,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=arm
GOARM=7
endif
ifeq (linux/arm/v6,$(findstring linux/arm/v6,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=arm
GOARM=6
endif
ifeq (linux/arm64,$(findstring linux/arm64,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=arm64
GOARM=7
endif
ifeq (linux/386,$(findstring linux/386,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=386
endif
ifeq (linux/amd64,$(findstring linux/amd64,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=amd64
endif
ifeq (linux/mips,$(findstring linux/mips,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=mips
endif
ifeq (linux/mipsle,$(findstring linux/mipsle,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=mipsle
endif
ifeq (linux/mips64,$(findstring linux/mips64,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=mips64
endif
ifeq (linux/mips64le,$(findstring linux/mips64le,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=mips64le
endif
ifeq (linux/riscv64,$(findstring linux/riscv64,$(TARGETPLATFORM)))
GOOS=linux
GOARCH=riscv64
endif
all: check build test install
.PHONY: all
@@ -70,14 +131,28 @@ install:
CGO_ENABLED=$(CGO_ENABLED) go install $(BUILD_FLAGS) -tags $(BUILD_TAGS) ./cmd/tendermint
.PHONY: install
###############################################################################
### Metrics ###
###############################################################################
metrics: testdata-metrics
go generate -run="scripts/metricsgen" ./...
.PHONY: metrics
# By convention, the go tool ignores subdirectories of directories named
# 'testdata'. This command invokes the generate command on the folder directly
# to avoid this.
testdata-metrics:
ls ./scripts/metricsgen/testdata | xargs -I{} go generate -v -run="scripts/metricsgen" ./scripts/metricsgen/testdata/{}
.PHONY: testdata-metrics
###############################################################################
### Mocks ###
###############################################################################
mockery:
mockery:
go generate -run="./scripts/mockery_generate.sh" ./...
.PHONY: mockery
.PHONY: mockery
###############################################################################
### Protobuf ###
@@ -85,7 +160,7 @@ mockery:
check-proto-deps:
ifeq (,$(shell which protoc-gen-gogofaster))
@go install github.com/gogo/protobuf/protoc-gen-gogofaster@latest
@go install github.com/cosmos/gogoproto/protoc-gen-gogofaster@latest
endif
.PHONY: check-proto-deps
@@ -99,6 +174,7 @@ 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
@@ -210,16 +286,33 @@ DESTINATION = ./index.html.md
### Documentation ###
###############################################################################
DOCS_OUTPUT?=/tmp/tendermint-core-docs
# This builds a docs site for each branch/tag in `./docs/versions` and copies
# each site to a version prefixed path. The last entry inside the `versions`
# file will be the default root index.html. Only redirects that are built into
# the "redirects" folder of each of the branches will be copied out to the root
# of the build at the end.
build-docs:
@cd docs && \
while read -r branch path_prefix; do \
(git checkout $${branch} && npm ci && VUEPRESS_BASE="/$${path_prefix}/" npm run build) ; \
mkdir -p ~/output/$${path_prefix} ; \
cp -r .vuepress/dist/* ~/output/$${path_prefix}/ ; \
cp ~/output/$${path_prefix}/index.html ~/output ; \
mkdir -p $(DOCS_OUTPUT)/$${path_prefix} ; \
cp -r .vuepress/dist/* $(DOCS_OUTPUT)/$${path_prefix}/ ; \
cp $(DOCS_OUTPUT)/$${path_prefix}/index.html $(DOCS_OUTPUT) ; \
cp $(DOCS_OUTPUT)/$${path_prefix}/404.html $(DOCS_OUTPUT) ; \
cp -r $(DOCS_OUTPUT)/$${path_prefix}/redirects/* $(DOCS_OUTPUT) || true ; \
done < versions ;
.PHONY: build-docs
# Build and serve the local version of the docs on the current branch from
# http://0.0.0.0:8080
serve-docs:
@cd docs && \
npm ci && \
npm run serve
.PHONY: serve-docs
sync-docs:
cd ~/output && \
echo "role_arn = ${DEPLOYMENT_ROLE_ARN}" >> /root/.aws/config ; \
@@ -228,6 +321,11 @@ sync-docs:
aws cloudfront create-invalidation --distribution-id ${CF_DISTRIBUTION_ID} --profile terraform --path "/*" ;
.PHONY: sync-docs
# Verify that important design docs have ToC entries.
check-docs-toc:
@./docs/presubmit.sh
.PHONY: check-docs-toc
###############################################################################
### Docker image ###
###############################################################################
@@ -244,7 +342,7 @@ build-docker: build-linux
# Build linux binary on other platforms
build-linux:
GOOS=linux GOARCH=amd64 $(MAKE) build
GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) $(MAKE) build
.PHONY: build-linux
build-docker-localnode:
@@ -308,4 +406,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=5m -race -coverprofile=$(BUILDDIR)/$*.profile.out
cat $(BUILDDIR)/packages.txt.$* | xargs go test -mod=readonly -timeout=15m -race -coverprofile=$(BUILDDIR)/$*.profile.out

214
README.md
View File

@@ -2,160 +2,174 @@
![banner](docs/tendermint-core-image.jpg)
[Byzantine-Fault Tolerant](https://en.wikipedia.org/wiki/Byzantine_fault_tolerance)
[State Machines](https://en.wikipedia.org/wiki/State_machine_replication).
Or [Blockchain](<https://en.wikipedia.org/wiki/Blockchain_(database)>), for short.
[Byzantine-Fault Tolerant][bft] [State Machine Replication][smr]. Or
[Blockchain], for short.
[![version](https://img.shields.io/github/tag/tendermint/tendermint.svg)](https://github.com/tendermint/tendermint/releases/latest)
[![API Reference](https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667)](https://pkg.go.dev/github.com/tendermint/tendermint)
[![Go version](https://img.shields.io/badge/go-1.15-blue.svg)](https://github.com/moovweb/gvm)
[![Discord chat](https://img.shields.io/discord/669268347736686612.svg)](https://discord.gg/AzefAFd)
[![license](https://img.shields.io/github/license/tendermint/tendermint.svg)](https://github.com/tendermint/tendermint/blob/master/LICENSE)
[![tendermint/tendermint](https://tokei.rs/b1/github/tendermint/tendermint?category=lines)](https://github.com/tendermint/tendermint)
[![Sourcegraph](https://sourcegraph.com/github.com/tendermint/tendermint/-/badge.svg)](https://sourcegraph.com/github.com/tendermint/tendermint?badge)
[![Version][version-badge]][version-url]
[![API Reference][api-badge]][api-url]
[![Go version][go-badge]][go-url]
[![Discord chat][discord-badge]][discord-url]
[![License][license-badge]][license-url]
[![Sourcegraph][sg-badge]][sg-url]
| Branch | Tests | Coverage | Linting |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
| master | [![CircleCI](https://circleci.com/gh/tendermint/tendermint/tree/master.svg?style=shield)](https://circleci.com/gh/tendermint/tendermint/tree/master) </br> ![Tests](https://github.com/tendermint/tendermint/workflows/Tests/badge.svg?branch=master) | [![codecov](https://codecov.io/gh/tendermint/tendermint/branch/master/graph/badge.svg)](https://codecov.io/gh/tendermint/tendermint) | ![Lint](https://github.com/tendermint/tendermint/workflows/Lint/badge.svg) |
| Branch | Tests | Linting |
|--------|------------------------------------|---------------------------------|
| main | [![Tests][tests-badge]][tests-url] | [![Lint][lint-badge]][lint-url] |
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.
Tendermint Core is a Byzantine Fault Tolerant (BFT) middleware that takes a
state transition machine - written in any programming language - and securely
replicates it on many machines.
For protocol details, see [the specification](https://github.com/tendermint/spec).
For protocol details, refer to the [Tendermint Specification](./spec/README.md).
For detailed analysis of the consensus protocol, including safety and liveness proofs,
see our recent paper, "[The latest gossip on BFT consensus](https://arxiv.org/abs/1807.04938)".
For detailed analysis of the consensus protocol, including safety and liveness
proofs, read our paper, "[The latest gossip on BFT
consensus](https://arxiv.org/abs/1807.04938)".
## Documentation
Complete documentation can be found on the
[website](https://docs.tendermint.com/).
## Releases
Please do not depend on master as your production branch. Use [releases](https://github.com/tendermint/tendermint/releases) instead.
Please do not depend on `main` as your production branch. Use
[releases](https://github.com/tendermint/tendermint/releases) instead.
Tendermint is being used in production in both private and public environments,
most notably the blockchains of the [Cosmos Network](https://cosmos.network/).
However, we are still making breaking changes to the protocol and the APIs and have not yet released v1.0.
See below for more details about [versioning](#versioning).
Tendermint has been in the production of private and public environments, most
notably the blockchains of the Cosmos Network. we haven't released v1.0 yet
since we are making breaking changes to the protocol and the APIs. See below for
more details about [versioning](#versioning).
In any case, if you intend to run Tendermint in production, we're happy to help. You can
contact us [over email](mailto:hello@interchain.berlin) or [join the chat](https://discord.gg/AzefAFd).
In any case, if you intend to run Tendermint in production, we're happy to help.
You can contact us [over email](mailto:hello@interchain.io) or [join the
chat](https://discord.gg/cosmosnetwork).
More on how releases are conducted can be found [here](./RELEASES.md).
## Security
To report a security vulnerability, see our [bug bounty
program](https://hackerone.com/tendermint).
For examples of the kinds of bugs we're looking for, see [our security policy](SECURITY.md)
program](https://hackerone.com/cosmos). For examples of the kinds of bugs we're
looking for, see [our security policy](SECURITY.md).
We also maintain a dedicated mailing list for security updates. We will only ever use this mailing list
to notify you of vulnerabilities and fixes in Tendermint Core. You can subscribe [here](http://eepurl.com/gZ5hQD).
We also maintain a dedicated mailing list for security updates. We will only
ever use this mailing list to notify you of vulnerabilities and fixes in
Tendermint Core. You can subscribe [here](http://eepurl.com/gZ5hQD).
## Minimum requirements
| Requirement | Notes |
| ----------- | ---------------- |
| Go version | Go1.15 or higher |
## Documentation
Complete documentation can be found on the [website](https://docs.tendermint.com/master/).
| Requirement | Notes |
|-------------|-------------------|
| Go version | Go 1.18 or higher |
### Install
See the [install instructions](/docs/introduction/install.md).
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)
- [Join the Cosmos testnet](https://cosmos.network/testnet)
- [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)
## Contributing
Please abide by the [Code of Conduct](CODE_OF_CONDUCT.md) in all interactions.
Before contributing to the project, please take a look at the [contributing guidelines](CONTRIBUTING.md)
and the [style guide](STYLE_GUIDE.md). You may also find it helpful to read the
[specifications](https://github.com/tendermint/spec), watch the [Developer Sessions](/docs/DEV_SESSIONS.md),
and familiarize yourself with our
[Architectural Decision Records](https://github.com/tendermint/tendermint/tree/master/docs/architecture).
Before contributing to the project, please take a look at the [contributing
guidelines](CONTRIBUTING.md) and the [style guide](STYLE_GUIDE.md). You may also
find it helpful to read the [specifications](./spec/README.md), and familiarize
yourself with our [Architectural Decision Records
(ADRs)](./docs/architecture/README.md) and
[Request For Comments (RFCs)](./docs/rfc/README.md).
## Versioning
### Semantic Versioning
Tendermint uses [Semantic Versioning](http://semver.org/) to determine when and how the version changes.
According to SemVer, anything in the public API can change at any time before version 1.0.0
Tendermint uses [Semantic Versioning](http://semver.org/) to determine when and
how the version changes. According to SemVer, anything in the public API can
change at any time before version 1.0.0
To provide some stability to Tendermint users in these 0.X.X days, the MINOR version is used
to signal breaking changes across a subset of the total public API. This subset includes all
interfaces exposed to other processes (cli, rpc, p2p, etc.), but does not
include the Go APIs.
To provide some stability to users of 0.X.X versions of Tendermint, the MINOR
version is used to signal breaking changes across Tendermint's API. This API
includes all publicly exposed types, functions, and methods in non-internal Go
packages as well as the types and methods accessible via the Tendermint RPC
interface.
That said, breaking changes in the following packages will be documented in the
CHANGELOG even if they don't lead to MINOR version bumps:
- crypto
- config
- libs
- bech32
- bits
- bytes
- json
- log
- math
- net
- os
- protoio
- rand
- sync
- strings
- service
- node
- rpc/client
- types
Breaking changes to these public APIs will be documented in the CHANGELOG.
### Upgrades
In an effort to avoid accumulating technical debt prior to 1.0.0,
we do not guarantee that breaking changes (ie. bumps in the MINOR version)
will work with existing Tendermint blockchains. In these cases you will
have to start a new blockchain, or write something custom to get the old
data into the new chain. However, any bump in the PATCH version should be
compatible with existing blockchain histories.
In an effort to avoid accumulating technical debt prior to 1.0.0, we do not
guarantee that breaking changes (ie. bumps in the MINOR version) will work with
existing Tendermint blockchains. In these cases you will have to start a new
blockchain, or write something custom to get the old data into the new chain.
However, any bump in the PATCH version should be compatible with existing
blockchain histories.
For more information on upgrading, see [UPGRADING.md](./UPGRADING.md).
### Supported Versions
Because we are a small core team, we only ship patch updates, including security updates,
to the most recent minor release and the second-most recent minor release. Consequently,
we strongly recommend keeping Tendermint up-to-date. Upgrading instructions can be found
in [UPGRADING.md](./UPGRADING.md).
Because we are a small core team, we only ship patch updates, including security
updates, to the most recent minor release and the second-most recent minor
release. Consequently, we strongly recommend keeping Tendermint up-to-date.
Upgrading instructions can be found in [UPGRADING.md](./UPGRADING.md).
## Resources
### Tendermint Core
### Libraries
For details about the blockchain data structures and the p2p protocols, see the
[Tendermint specification](https://docs.tendermint.com/master/spec/).
For details on using the software, see the [documentation](/docs/) which is also
hosted at: <https://docs.tendermint.com/master/>
### Tools
Benchmarking is provided by [`tm-load-test`](https://github.com/informalsystems/tm-load-test).
Additional tooling can be found in [/docs/tools](/docs/tools).
- [Cosmos SDK](http://github.com/cosmos/cosmos-sdk); A framework for building
applications in Golang
- [Tendermint in Rust](https://github.com/informalsystems/tendermint-rs)
- [ABCI Tower](https://github.com/penumbra-zone/tower-abci)
### Applications
- [Cosmos SDK](http://github.com/cosmos/cosmos-sdk); a cryptocurrency application framework
- [Ethermint](http://github.com/cosmos/ethermint); Ethereum on Tendermint
- [Many more](https://tendermint.com/ecosystem)
- [Cosmos Hub](https://hub.cosmos.network/)
- [Terra](https://www.terra.money/)
- [Celestia](https://celestia.org/)
- [Anoma](https://anoma.network/)
- [Vocdoni](https://docs.vocdoni.io/)
### Research
- [The latest gossip on BFT consensus](https://arxiv.org/abs/1807.04938)
- [Master's Thesis on Tendermint](https://atrium.lib.uoguelph.ca/xmlui/handle/10214/9769)
- [Original Whitepaper: "Tendermint: Consensus Without Mining"](https://tendermint.com/static/docs/tendermint.pdf)
- [Blog](https://blog.cosmos.network/tendermint/home)
- [Tendermint Core Blog](https://medium.com/tendermint/tagged/tendermint-core)
- [Cosmos Blog](https://blog.cosmos.network/tendermint/home)
## Join us!
Tendermint Core is maintained by [Interchain GmbH](https://interchain.io).
If you'd like to work full-time on Tendermint Core,
[we're hiring](https://interchain-gmbh.breezy.hr/)!
Funding for Tendermint Core development comes primarily from the
[Interchain Foundation](https://interchain.io), a Swiss non-profit. The
Tendermint trademark is owned by [Tendermint Inc.](https://tendermint.com), the
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-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
[go-badge]: https://img.shields.io/badge/go-1.18-blue.svg
[go-url]: https://github.com/moovweb/gvm
[discord-badge]: https://img.shields.io/discord/669268347736686612.svg
[discord-url]: https://discord.gg/cosmosnetwork
[license-badge]: https://img.shields.io/github/license/tendermint/tendermint.svg
[license-url]: https://github.com/tendermint/tendermint/blob/main/LICENSE
[sg-badge]: https://sourcegraph.com/github.com/tendermint/tendermint/-/badge.svg
[sg-url]: https://sourcegraph.com/github.com/tendermint/tendermint?badge
[tests-url]: https://github.com/tendermint/tendermint/actions/workflows/tests.yml
[tests-badge]: https://github.com/tendermint/tendermint/actions/workflows/tests.yml/badge.svg?branch=main
[lint-badge]: https://github.com/tendermint/tendermint/actions/workflows/lint.yml/badge.svg
[lint-url]: https://github.com/tendermint/tendermint/actions/workflows/lint.yml

371
RELEASES.md Normal file
View File

@@ -0,0 +1,371 @@
# Releases
Tendermint uses modified [semantic versioning](https://semver.org/) with each
release following a `vX.Y.Z` format. Tendermint is currently on major version 0
and uses the minor version to signal breaking changes. The `main` branch is
used for active development and thus it is not advisable to build against it.
The latest changes are always initially merged into `main`. Releases are
specified using tags and are built from long-lived "backport" branches that are
cut from `main` when the release process begins. Each release "line" (e.g.
0.34 or 0.33) has its own long-lived backport branch, and the backport branches
have names like `v0.34.x` or `v0.33.x` (literally, `x`; it is not a placeholder
in this case). Tendermint only maintains the last two releases at a time (the
oldest release is predominantly just security patches).
## Backporting
As non-breaking changes land on `main`, they should also be backported to
these backport branches.
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
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.
### Creating a backport branch
If this is the first release candidate for a minor version release, e.g.
v0.25.0, you get to have the honor of creating the backport branch!
Note that, after creating the backport branch, you'll also need to update the
tags on `main` so that `go mod` is able to order the branches correctly. You
should tag `main` with a "dev" tag that is "greater than" the backport
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.
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:
```sh
git checkout -b v0.38.x
git push origin v0.38.x
```
4. 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:
* [`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:
```sh
# 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
```
Be sure to merge this PR before making other changes on the newly-created
backport branch.
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
[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`
[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
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
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:
- `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.
(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:
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.
- 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`
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.
## Minor release
This minor release process assumes that this release was preceded by release
candidates. If there were no release candidates, begin by creating a backport
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`)
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.)
- 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.
- Bump TMVersionDefault version in `version.go`
- Bump P2P and block protocol versions in `version.go`, if necessary
- 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`
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:
- 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.
- Add a new entry to `themeConfig.versions` in
[`docs/.vuepress/config.js`](./docs/.vuepress/config.js) to include the
release in the dropdown versions menu.
- Commit these changes to `main` and backport them into the backport
branch for this release.
## Patch release
Patch releases are done differently from minor releases: They are built off of
long-lived backport branches, rather than from main. As non-breaking changes
land on `main`, they should also be backported into these backport branches.
Patch releases don't have release candidates by default, although any tricky
changes may merit a release candidate.
To create a patch release:
1. Checkout the long-lived backport branch: `git checkout v0.38.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`
- Run `python ./scripts/linkify_changelog.py CHANGELOG.md` to add links for all issues
- Run `bash ./scripts/authors.sh` to get a list of authors since the latest release, and add the GitHub aliases of external contributors to the top of the CHANGELOG. To lookup an alias from an email, try `bash ./scripts/authors.sh <email>`
- Reset the `CHANGELOG_PENDING.md`
- Bump the TMDefaultVersion in `version.go`
- 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`
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`
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.
## Minor Release Checklist
The following set of steps are performed on all releases that increment the
_minor_ version, e.g. v0.25 to v0.26. These steps ensure that Tendermint is well
tested, stable, and suitable for adoption by the various diverse projects that
rely on Tendermint.
### Feature Freeze
Ahead of any minor version release of Tendermint, the software enters 'Feature
Freeze' for at least two weeks. A feature freeze means that _no_ new features
are added to the code being prepared for release. No code changes should be made
to the code being released that do not directly improve pressing issues of code
quality. The following must not be merged during a feature freeze:
* Refactors that are not related to specific bug fixes.
* Dependency upgrades.
* New test code that does not test a discovered regression.
* New features of any kind.
* Documentation or spec improvements that are not related to the newly developed
code.
This period directly follows the creation of the [backport
branch](#creating-a-backport-branch). The Tendermint team instead directs all
attention to ensuring that the existing code is stable and reliable. Broken
tests are fixed, flakey-tests are remedied, end-to-end test failures are
thoroughly diagnosed and all efforts of the team are aimed at improving the
quality of the code. During this period, the upgrade harness tests are run
repeatedly and a variety of in-house testnets are run to ensure Tendermint
functions at the scale it will be used by application developers and node
operators.
### Nightly End-To-End Tests
The Tendermint team maintains [a set of end-to-end
tests](https://github.com/tendermint/tendermint/blob/main/test/e2e/README.md#L1)
that run each night on the latest commit of the project and on the code in the
tip of each supported backport branch. These tests start a network of
containerized Tendermint processes and run automated checks that the network
functions as expected in both stable and unstable conditions. During the feature
freeze, these tests are run nightly and must pass consistently for a release of
Tendermint to be considered stable.
### Upgrade Harness
> TODO(williambanfield): Change to past tense and clarify this section once
> upgrade harness is complete.
The Tendermint team is creating an upgrade test harness to exercise the workflow
of stopping an instance of Tendermint running one version of the software and
starting up the same application running the next version. To support upgrade
testing, we will add the ability to terminate the Tendermint process at specific
pre-defined points in its execution so that we can verify upgrades work in a
representative sample of stop conditions.
### Large Scale Testnets
The Tendermint end-to-end tests run a small network (~10s of nodes) to exercise
basic consensus interactions. Real world deployments of Tendermint often have
over a hundred nodes just in the validator set, with many others acting as full
nodes and sentry nodes. To gain more assurance before a release, we will also
run larger-scale test networks to shake out emergent behaviors at scale.
Large-scale test networks are run on a set of virtual machines (VMs). Each VM is
equipped with 4 Gigabytes of RAM and 2 CPU cores. The network runs a very simple
key-value store application. The application adds artificial delays to different
ABCI calls to simulate a slow application. Each testnet is briefly run with no
load being generated to collect a baseline performance. Once baseline is
captured, a consistent load is applied across the network. This load takes the
form of 10% of the running nodes all receiving a consistent stream of two
hundred transactions per minute each.
During each test net, the following metrics are monitored and collected on each
node:
* Consensus rounds per height
* Maximum connected peers, Minimum connected peers, Rate of change of peer connections
* Memory resident set size
* CPU utilization
* Blocks produced per minute
* Seconds for each step of consensus (Propose, Prevote, Precommit, Commit)
* Latency to receive block proposals
For these tests we intentionally target low-powered host machines (with low core
counts and limited memory) to ensure we observe similar kinds of resource contention
and limitation that real-world deployments of Tendermint experience in production.
#### 200 Node Testnet
To test the stability and performance of Tendermint in a real world scenario,
a 200 node test network is run. The network comprises 5 seed nodes, 100
validators and 95 non-validating full nodes. All nodes begin by dialing
a subset of the seed nodes to discover peers. The network is run for several
days, with metrics being collected continuously. In cases of changes to performance
critical systems, testnets of larger sizes should be considered.
#### Rotating Node Testnet
Real-world deployments of Tendermint frequently see new nodes arrive and old
nodes exit the network. The rotating node testnet ensures that Tendermint is
able to handle this reliably. In this test, a network with 10 validators and
3 seed nodes is started. A rolling set of 25 full nodes are started and each
connects to the network by dialing one of the seed nodes. Once the node is able
to blocksync to the head of the chain and begins producing blocks using
Tendermint consensus it is stopped. Once stopped, a new node is started and
takes its place. This network is run for several days.
#### Network Partition Testnet
Tendermint is expected to recover from network partitions. A partition where no
subset of the nodes is left with the super-majority of the stake is expected to
stop making blocks. Upon alleviation of the partition, the network is expected
to once again become fully connected and capable of producing blocks. The
network partition testnet ensures that Tendermint is able to handle this
reliably at scale. In this test, a network with 100 validators and 95 full
nodes is started. All validators have equal stake. Once the network is
producing blocks, a set of firewall rules is deployed to create a partitioned
network with 50% of the stake on one side and 50% on the other. Once the
network stops producing blocks, the firewall rules are removed and the nodes
are monitored to ensure they reconnect and that the network again begins
producing blocks.
#### Absent Stake Testnet
Tendermint networks often run with _some_ portion of the voting power offline.
The absent stake testnet ensures that large networks are able to handle this
reliably. A set of 150 validator nodes and three seed nodes is started. The set
of 150 validators is configured to only possess a cumulative stake of 67% of
the total stake. The remaining 33% of the stake is configured to belong to
a validator that is never actually run in the test network. The network is run
for multiple days, ensuring that it is able to produce blocks without issue.

View File

@@ -2,98 +2,146 @@
## Reporting a Bug
As part of our [Coordinated Vulnerability Disclosure
Policy](https://tendermint.com/security), we operate a [bug
bounty](https://hackerone.com/tendermint).
See the policy for more details on submissions and rewards, and see "Example Vulnerabilities" (below) for examples of the kinds of bugs we're most interested in.
As part of our [Coordinated Vulnerability Disclosure Policy](https://tendermint.com/security),
we operate a [bug bounty][hackerone]. See the policy for more
details on submissions and rewards, and see "Example Vulnerabilities" (below)
for examples of the kinds of bugs we're most interested in.
### Guidelines
### Guidelines
We require that all researchers:
* Use the bug bounty to disclose all vulnerabilities, and avoid posting vulnerability information in public places, including Github Issues, Discord channels, and Telegram groups
* Make every effort to avoid privacy violations, degradation of user experience, disruption to production systems (including but not limited to the Cosmos Hub), and destruction of data
* Keep any information about vulnerabilities that youve discovered confidential between yourself and the Tendermint Core engineering team until the issue has been resolved and disclosed
* Use the bug bounty to disclose all vulnerabilities, and avoid posting
vulnerability information in public places, including Github Issues, Discord
channels, and Telegram groups
* Make every effort to avoid privacy violations, degradation of user experience,
disruption to production systems (including but not limited to the Cosmos
Hub), and destruction of data
* Keep any information about vulnerabilities that youve discovered confidential
between yourself and the Tendermint Core engineering team until the issue has
been resolved and disclosed
* Avoid posting personally identifiable information, privately or publicly
If you follow these guidelines when reporting an issue to us, we commit to:
* Not pursue or support any legal action related to your research on this vulnerability
* Work with you to understand, resolve and ultimately disclose the issue in a timely fashion
* Not pursue or support any legal action related to your research on this
vulnerability
* Work with you to understand, resolve and ultimately disclose the issue in a
timely fashion
## Disclosure Process
## Disclosure Process
Tendermint Core uses the following disclosure process:
1. Once a security report is received, the Tendermint Core team works to verify the issue and confirm its severity level using CVSS.
2. The Tendermint Core team collaborates with the Gaia team to determine the vulnerabilitys potential impact on the Cosmos Hub.
3. Patches are prepared for eligible releases of Tendermint in private repositories. See “Supported Releases” below for more information on which releases are considered eligible.
4. If it is determined that a CVE-ID is required, we request a CVE through a CVE Numbering Authority.
5. We notify the community that a security release is coming, to give users time to prepare their systems for the update. Notifications can include forum posts, tweets, and emails to partners and validators, including emails sent to the [Tendermint Security Mailing List](https://berlin.us4.list-manage.com/subscribe?u=431b35421ff7edcc77df5df10&id=3fe93307bc).
6. 24 hours following this notification, the fixes are applied publicly and new releases are issued.
7. Cosmos SDK and Gaia update their Tendermint Core dependencies to use these releases, and then themselves issue new releases.
8. Once releases are available for Tendermint Core, Cosmos SDK and Gaia, we notify the community, again, through the same channels as above. We also publish a Security Advisory on Github and publish the CVE, as long as neither the Security Advisory nor the CVE include any information on how to exploit these vulnerabilities beyond what information is already available in the patch itself.
9. Once the community is notified, we will pay out any relevant bug bounties to submitters.
10. One week after the releases go out, we will publish a post with further details on the vulnerability as well as our response to it.
1. Once a security report is received, the Tendermint Core team works to verify
the issue and confirm its severity level using CVSS.
2. The Tendermint Core team collaborates with the Gaia team to determine the
vulnerabilitys potential impact on the Cosmos Hub.
3. Patches are prepared for eligible releases of Tendermint in private
repositories. See “Supported Releases” below for more information on which
releases are considered eligible.
4. If it is determined that a CVE-ID is required, we request a CVE through a CVE
Numbering Authority.
5. We notify the community that a security release is coming, to give users time
to prepare their systems for the update. Notifications can include forum
posts, tweets, and emails to partners and validators, including emails sent
to the [Tendermint Security Mailing List][tmsec-mailing].
6. 24 hours following this notification, the fixes are applied publicly and new
releases are issued.
7. Cosmos SDK and Gaia update their Tendermint Core dependencies to use these
releases, and then themselves issue new releases.
8. Once releases are available for Tendermint Core, Cosmos SDK and Gaia, we
notify the community, again, through the same channels as above. We also
publish a Security Advisory on Github and publish the CVE, as long as neither
the Security Advisory nor the CVE include any information on how to exploit
these vulnerabilities beyond what information is already available in the
patch itself.
9. Once the community is notified, we will pay out any relevant bug bounties to
submitters.
10. One week after the releases go out, we will publish a post with further
details on the vulnerability as well as our response to it.
This process can take some time. Every effort will be made to handle the bug in as timely a manner as possible, however it's important that we follow the process described above to ensure that disclosures are handled consistently and to keep Tendermint Core and its downstream dependent projects--including but not limited to Gaia and the Cosmos Hub--as secure as possible.
This process can take some time. Every effort will be made to handle the bug in
as timely a manner as possible, however it's important that we follow the
process described above to ensure that disclosures are handled consistently and
to keep Tendermint Core and its downstream dependent projects--including but not
limited to Gaia and the Cosmos Hub--as secure as possible.
### Example Timeline
### Example Timeline
The following is an example timeline for the triage and response. The required roles and team members are described in parentheses after each task; however, multiple people can play each role and each person may play multiple roles.
The following is an example timeline for the triage and response. The required
roles and team members are described in parentheses after each task; however,
multiple people can play each role and each person may play multiple roles.
#### > 24 Hours Before Release Time
#### 24+ Hours Before Release Time
1. Request CVE number (ADMIN)
2. Gather emails and other contact info for validators (COMMS LEAD)
3. Test fixes on a testnet (TENDERMINT ENG, COSMOS ENG)
4. Write “Security Advisory” for forum (TENDERMINT LEAD)
1. Request CVE number (ADMIN)
2. Gather emails and other contact info for validators (COMMS LEAD)
3. Create patches in a private security repo, and ensure that PRs are open
targeting all relevant release branches (TENDERMINT ENG, TENDERMINT LEAD)
4. Test fixes on a testnet (TENDERMINT ENG, COSMOS SDK ENG)
5. Write “Security Advisory” for forum (TENDERMINT LEAD)
#### 24 Hours Before Release Time
1. Post “Security Advisory” pre-notification on forum (TENDERMINT LEAD)
2. Post Tweet linking to forum post (COMMS LEAD)
3. Announce security advisory/link to post in various other social channels (Telegram, Discord) (COMMS LEAD)
4. Send emails to validators or other users (PARTNERSHIPS LEAD)
1. Post “Security Advisory” pre-notification on forum (TENDERMINT LEAD)
2. Post Tweet linking to forum post (COMMS LEAD)
3. Announce security advisory/link to post in various other social channels
(Telegram, Discord) (COMMS LEAD)
4. Send emails to validators or other users (PARTNERSHIPS LEAD)
#### Release Time
1. Cut Tendermint releases for eligible versions (TENDERMINT ENG, TENDERMINT LEAD)
1. Cut Tendermint releases for eligible versions (TENDERMINT ENG, TENDERMINT
LEAD)
2. Cut Cosmos SDK release for eligible versions (COSMOS ENG)
3. Cut Gaia release for eligible versions (GAIA ENG)
4. Post “Security releases” on forum (TENDERMINT LEAD)
5. Post new Tweet linking to forum post (COMMS LEAD)
6. Remind everyone via social channels (Telegram, Discord) that the release is out (COMMS LEAD)
7. Send emails to validators or other users (COMMS LEAD)
8. Publish Security Advisory and CVE, if CVE has no sensitive information (ADMIN)
6. Remind everyone via social channels (Telegram, Discord) that the release is
out (COMMS LEAD)
7. Send emails to validators or other users (COMMS LEAD)
8. Publish Security Advisory and CVE, if CVE has no sensitive information
(ADMIN)
#### After Release Time
1. Write forum post with exploit details (TENDERMINT LEAD)
2. Approve pay-out on HackerOne for submitter (ADMIN)
2. Approve pay-out on HackerOne for submitter (ADMIN)
#### 7 Days After Release Time
1. Publish CVE if it has not yet been published (ADMIN)
1. Publish CVE if it has not yet been published (ADMIN)
2. Publish forum post with exploit details (TENDERMINT ENG, TENDERMINT LEAD)
## Supported Releases
The Tendermint Core team commits to releasing security patch releases for both the latest minor release as well for the major/minor release that the Cosmos Hub is running.
The Tendermint Core team commits to releasing security patch releases for both
the latest minor release as well for the major/minor release that the Cosmos Hub
is running.
If you are running older versions of Tendermint Core, we encourage you to upgrade at your earliest opportunity so that you can receive security patches directly from the Tendermint repo. While you are welcome to backport security patches to older versions for your own use, we will not publish or promote these backports.
If you are running older versions of Tendermint Core, we encourage you to
upgrade at your earliest opportunity so that you can receive security patches
directly from the Tendermint repo. While you are welcome to backport security
patches to older versions for your own use, we will not publish or promote these
backports.
## Scope
The full scope of our bug bounty program is outlined on our [Hacker One program page](https://hackerone.com/tendermint). Please also note that, in the interest of the safety of our users and staff, a few things are explicitly excluded from scope:
The full scope of our bug bounty program is outlined on our
[Hacker One program page][hackerone]. Please also note that, in the interest of
the safety of our users and staff, a few things are explicitly excluded from
scope:
* Any third-party services
* Findings from physical testing, such as office access
* Any third-party services
* Findings from physical testing, such as office access
* Findings derived from social engineering (e.g., phishing)
## Example Vulnerabilities
## Example Vulnerabilities
The following is a list of examples of the kinds of vulnerabilities that were most interested in. It is not exhaustive: there are other kinds of issues we may also be interested in!
The following is a list of examples of the kinds of vulnerabilities that were
most interested in. It is not exhaustive: there are other kinds of issues we may
also be interested in!
### Specification
@@ -105,7 +153,8 @@ The following is a list of examples of the kinds of vulnerabilities that were
Assuming less than 1/3 of the voting power is Byzantine (malicious):
* Validation of blockchain data structures, including blocks, block parts, votes, and so on
* Validation of blockchain data structures, including blocks, block parts,
votes, and so on
* Execution of blocks
* Validator set changes
* Proposer round robin
@@ -114,6 +163,9 @@ Assuming less than 1/3 of the voting power is Byzantine (malicious):
* A node halting (liveness failure)
* Syncing new and old nodes
Assuming more than 1/3 the voting power is Byzantine:
* Attacks that go unpunished (unhandled evidence)
### Networking
@@ -139,7 +191,7 @@ Attacks may come through the P2P network or the RPC layer:
### Libraries
* Serialization (Amino)
* Serialization
* Reading/Writing files and databases
### Cryptography
@@ -150,5 +202,8 @@ Attacks may come through the P2P network or the RPC layer:
### Light Client
* Core verification
* Core verification
* Bisection/sequential algorithms
[hackerone]: https://hackerone.com/cosmos
[tmsec-mailing]: https://berlin.us4.list-manage.com/subscribe?u=431b35421ff7edcc77df5df10&id=3fe93307bc

View File

@@ -1,6 +1,36 @@
# Upgrading Tendermint Core
This guide provides instructions for upgrading to specific versions of Tendermint Core.
This guide provides instructions for upgrading to specific versions of
Tendermint Core.
## Unreleased
### ABCI Changes
* The `ABCIVersion` is now `1.0.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)
* 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.
In-process applications should make sure they are not using the deleted
version of those structures.
* In v0.34, messages on the wire used to be length-delimited with `int64` varint
values, which was inconsistent with the `uint64` varint length delimiters used
in the P2P layer. Both now consistently use `uint64` varint length delimiters.
* Added `AbciVersion` to `RequestInfo`.
Applications should check that Tendermint's ABCI version matches the one they expect
in order to ensure compatibility.
* The `SetOption` method has been removed from the ABCI `Client` interface.
The corresponding Protobuf types have been deprecated.
* The `key` and `value` fields in the `EventAttribute` type have been changed
from type `bytes` to `string`. As per the [Protocol Buffers updating
guidelines](https://developers.google.com/protocol-buffers/docs/proto3#updating),
this should have no effect on the wire-level encoding for UTF8-encoded
strings.
## v0.34.20
@@ -15,7 +45,7 @@ and gas cost).
Operators can enable the priority mempool by setting `mempool.version` to
`"v1"` in the `config.toml`. For more technical details about the priority
mempool, see [ADR 067: Mempool
Refactor](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-067-mempool-refactor.md).
Refactor](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-067-mempool-refactor.md).
## v0.34.0
@@ -23,7 +53,7 @@ Refactor](https://github.com/tendermint/tendermint/blob/master/docs/architecture
This release is not compatible with previous blockchains due to changes to
the encoding format (see "Protocol Buffers," below) and the block header (see "Blockchain Protocol").
Note also that Tendermint 0.34 also requires Go 1.15 or higher.
Note also that Tendermint 0.34 also requires Go 1.16 or higher.
### ABCI Changes
@@ -33,7 +63,7 @@ Note also that Tendermint 0.34 also requires Go 1.15 or higher.
were added to support the new State Sync feature.
Previously, syncing a new node to a preexisting network could take days; but with State Sync,
new nodes are able to join a network in a matter of seconds.
Read [the spec](https://docs.tendermint.com/master/spec/abci/apps.html#state-sync)
Read [the spec](https://github.com/tendermint/tendermint/blob/v0.34.x/spec/abci/apps.md#state-sync)
if you want to learn more about State Sync, or if you'd like your application to use it.
(If you don't want to support State Sync in your application, you can just implement these new
ABCI methods as no-ops, leaving them empty.)
@@ -49,7 +79,7 @@ Note also that Tendermint 0.34 also requires Go 1.15 or higher.
Applications should be able to handle these evidence types
(i.e., through slashing or other accountability measures).
* The [`PublicKey` type](https://github.com/tendermint/tendermint/blob/master/proto/tendermint/crypto/keys.proto#L13-L15)
* The [`PublicKey` type](https://github.com/tendermint/tendermint/blob/main/proto/tendermint/crypto/keys.proto#L13-L15)
(used in ABCI as part of `ValidatorUpdate`) now uses a `oneof` protobuf type.
Note that since Tendermint only supports ed25519 validator keys, there's only one
option in the `oneof`. For more, see "Protocol Buffers," below.
@@ -64,12 +94,9 @@ directory. For more, see "Protobuf," below.
### Blockchain Protocol
* `Header#LastResultsHash` previously was the root hash of a Merkle tree built from `ResponseDeliverTx(Code, Data)` responses.
As of 0.34,`Header#LastResultsHash` is now the root hash of a Merkle tree built from:
* `BeginBlock#Events`
* Root hash of a Merkle tree built from `ResponseDeliverTx(Code, Data,
GasWanted, GasUsed, Events)` responses
* `BeginBlock#Events`
* `Header#LastResultsHash`, which is the root hash of a Merkle tree built from
`ResponseDeliverTx(Code, Data)` as of v0.34 also includes `GasWanted` and `GasUsed`
fields.
* Merkle hashes of empty trees previously returned nothing, but now return the hash of an empty input,
to conform with [RFC-6962](https://tools.ietf.org/html/rfc6962).
@@ -159,7 +186,7 @@ The `bech32` package has moved to the Cosmos SDK:
### CLI
The `tendermint lite` command has been renamed to `tendermint light` and has a slightly different API.
See [the docs](https://docs.tendermint.com/master/tendermint-core/light-client-protocol.html#http-proxy) for details.
See [the docs](https://docs.tendermint.com/v0.33/tendermint-core/light-client-protocol.html#http-proxy) for details.
### Light Client
@@ -173,6 +200,7 @@ Other user-relevant changes include:
* The `Verifier` was broken up into two pieces:
* Core verification logic (pure `VerifyX` functions)
* `Client` object, which represents the complete light client
* The new light client stores headers and validator sets as `LightBlock`s
* The RPC client can be found in the `/rpc` directory.
* The HTTP(S) proxy is located in the `/proxy` directory.
@@ -314,7 +342,7 @@ Evidence Params has been changed to include duration.
### RPC Changes
* `/validators` is now paginated (default: 30 vals per page)
* `/block_results` response format updated [see RPC docs for details](https://docs.tendermint.com/master/rpc/#/Info/block_results)
* `/block_results` response format updated [see RPC docs for details](https://docs.tendermint.com/v0.33/rpc/#/Info/block_results)
* Event suffix has been removed from the ID in event responses
* IDs are now integers not `json-client-XYZ`
@@ -433,11 +461,11 @@ the compilation tag:
Use `cleveldb` tag instead of `gcc` to compile Tendermint with CLevelDB or
use `make build_c` / `make install_c` (full instructions can be found at
<https://tendermint.com/docs/introduction/install.html#compile-with-cleveldb-support>)
<https://docs.tendermint.com/v0.33/introduction/install.html#compile-with-cleveldb-support>)
## v0.31.0
This release contains a breaking change to the behaviour of the pubsub system.
This release contains a breaking change to the behavior of the pubsub system.
It also contains some minor breaking changes in the Go API and ABCI.
There are no changes to the block or p2p protocols, so v0.31.0 should work fine
with blockchains created from the v0.30 series.
@@ -455,7 +483,7 @@ In this case, the WS client will receive an error with description:
"error": {
"code": -32000,
"msg": "Server error",
"data": "subscription was cancelled (reason: client is not pulling messages fast enough)" // or "subscription was cancelled (reason: Tendermint exited)"
"data": "subscription was canceled (reason: client is not pulling messages fast enough)" // or "subscription was canceled (reason: Tendermint exited)"
}
}
@@ -508,14 +536,14 @@ due to changes in how various data structures are hashed.
Any implementations of Tendermint blockchain verification, including lite clients,
will need to be updated. For specific details:
* [Merkle tree](https://github.com/tendermint/spec/blob/master/spec/blockchain/encoding.md#merkle-trees)
* [ConsensusParams](https://github.com/tendermint/spec/blob/master/spec/blockchain/state.md#consensusparams)
* [Merkle tree](https://github.com/tendermint/tendermint/blob/main/spec/blockchain/encoding.md#merkle-trees)
* [ConsensusParams](https://github.com/tendermint/tendermint/blob/main/spec/blockchain/state.md#consensusparams)
There was also a small change to field ordering in the vote struct. Any
implementations of an out-of-process validator (like a Key-Management Server)
will need to be updated. For specific details:
* [Vote](https://github.com/tendermint/spec/blob/master/spec/consensus/signing.md#votes)
* [Vote](https://github.com/tendermint/tendermint/blob/main/spec/consensus/signing.md#votes)
Finally, the proposer selection algorithm continues to evolve. See the
[work-in-progress
@@ -636,7 +664,7 @@ to `timeout_propose = "3s"`.
### RPC Changes
The default behaviour of `/abci_query` has been changed to not return a proof,
The default behavior of `/abci_query` has been changed to not return a proof,
and the name of the parameter that controls this has been changed from `trusted`
to `prove`. To get proofs with your queries, ensure you set `prove=true`.

View File

@@ -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/spec/blob/master/spec/abci/abci.md)
- [A protobuf file](./types/types.proto)
- [The main spec](https://github.com/tendermint/tendermint/blob/main/spec/abci/README.md)
- [A protobuf file](../proto/tendermint/types/types.proto)
- [A Go interface](./types/application.go)
## Protocol Buffers

View File

@@ -14,7 +14,7 @@ const (
echoRetryIntervalSeconds = 1
)
//go:generate mockery --case underscore --name Client
//go:generate ../../scripts/mockery_generate.sh Client
// Client defines an interface for an ABCI client.
// All `Async` methods return a `ReqRes` object.
@@ -30,7 +30,6 @@ type Client interface {
FlushAsync() *ReqRes
EchoAsync(msg string) *ReqRes
InfoAsync(types.RequestInfo) *ReqRes
SetOptionAsync(types.RequestSetOption) *ReqRes
DeliverTxAsync(types.RequestDeliverTx) *ReqRes
CheckTxAsync(types.RequestCheckTx) *ReqRes
QueryAsync(types.RequestQuery) *ReqRes
@@ -43,11 +42,11 @@ type Client interface {
OfferSnapshotAsync(types.RequestOfferSnapshot) *ReqRes
LoadSnapshotChunkAsync(types.RequestLoadSnapshotChunk) *ReqRes
ApplySnapshotChunkAsync(types.RequestApplySnapshotChunk) *ReqRes
ProcessProposalAsync(types.RequestProcessProposal) *ReqRes
FlushSync() error
EchoSync(msg string) (*types.ResponseEcho, error)
InfoSync(types.RequestInfo) (*types.ResponseInfo, error)
SetOptionSync(types.RequestSetOption) (*types.ResponseSetOption, error)
DeliverTxSync(types.RequestDeliverTx) (*types.ResponseDeliverTx, error)
CheckTxSync(types.RequestCheckTx) (*types.ResponseCheckTx, error)
QuerySync(types.RequestQuery) (*types.ResponseQuery, error)
@@ -60,6 +59,7 @@ type Client interface {
OfferSnapshotSync(types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error)
LoadSnapshotChunkSync(types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error)
ApplySnapshotChunkSync(types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error)
ProcessProposalSync(types.RequestProcessProposal) (*types.ResponseProcessProposal, error)
}
//----------------------------------------

View File

@@ -192,15 +192,6 @@ func (cli *grpcClient) InfoAsync(params types.RequestInfo) *ReqRes {
return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Info{Info: res}})
}
func (cli *grpcClient) SetOptionAsync(params types.RequestSetOption) *ReqRes {
req := types.ToRequestSetOption(params)
res, err := cli.client.SetOption(context.Background(), req.GetSetOption(), grpc.WaitForReady(true))
if err != nil {
cli.StopForError(err)
}
return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_SetOption{SetOption: res}})
}
func (cli *grpcClient) DeliverTxAsync(params types.RequestDeliverTx) *ReqRes {
req := types.ToRequestDeliverTx(params)
res, err := cli.client.DeliverTx(context.Background(), req.GetDeliverTx(), grpc.WaitForReady(true))
@@ -309,6 +300,16 @@ func (cli *grpcClient) PrepareProposalAsync(params types.RequestPrepareProposal)
return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_PrepareProposal{PrepareProposal: res}})
}
func (cli *grpcClient) ProcessProposalAsync(params types.RequestProcessProposal) *ReqRes {
req := types.ToRequestProcessProposal(params)
res, err := cli.client.ProcessProposal(context.Background(), req.GetProcessProposal(), grpc.WaitForReady(true))
if err != nil {
cli.StopForError(err)
}
return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_ProcessProposal{ProcessProposal: res}})
}
// finishAsyncCall creates a ReqRes for an async call, and immediately populates it
// with the response. We don't complete it until it's been ordered via the channel.
func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) *ReqRes {
@@ -365,11 +366,6 @@ func (cli *grpcClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, err
return cli.finishSyncCall(reqres).GetInfo(), cli.Error()
}
func (cli *grpcClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
reqres := cli.SetOptionAsync(req)
return reqres.Response.GetSetOption(), cli.Error()
}
func (cli *grpcClient) DeliverTxSync(params types.RequestDeliverTx) (*types.ResponseDeliverTx, error) {
reqres := cli.DeliverTxAsync(params)
return cli.finishSyncCall(reqres).GetDeliverTx(), cli.Error()
@@ -432,3 +428,8 @@ func (cli *grpcClient) PrepareProposalSync(
reqres := cli.PrepareProposalAsync(params)
return cli.finishSyncCall(reqres).GetPrepareProposal(), cli.Error()
}
func (cli *grpcClient) ProcessProposalSync(params types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
reqres := cli.ProcessProposalAsync(params)
return cli.finishSyncCall(reqres).GetProcessProposal(), cli.Error()
}

View File

@@ -75,17 +75,6 @@ func (app *localClient) InfoAsync(req types.RequestInfo) *ReqRes {
)
}
func (app *localClient) SetOptionAsync(req types.RequestSetOption) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.SetOption(req)
return app.callback(
types.ToRequestSetOption(req),
types.ToResponseSetOption(res),
)
}
func (app *localClient) DeliverTxAsync(params types.RequestDeliverTx) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
@@ -218,6 +207,17 @@ func (app *localClient) PrepareProposalAsync(req types.RequestPrepareProposal) *
)
}
func (app *localClient) ProcessProposalAsync(req types.RequestProcessProposal) *ReqRes {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.ProcessProposal(req)
return app.callback(
types.ToRequestProcessProposal(req),
types.ToResponseProcessProposal(res),
)
}
//-------------------------------------------------------
func (app *localClient) FlushSync() error {
@@ -236,14 +236,6 @@ func (app *localClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, er
return &res, nil
}
func (app *localClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.SetOption(req)
return &res, nil
}
func (app *localClient) DeliverTxSync(req types.RequestDeliverTx) (*types.ResponseDeliverTx, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
@@ -342,6 +334,14 @@ func (app *localClient) PrepareProposalSync(req types.RequestPrepareProposal) (*
return &res, nil
}
func (app *localClient) ProcessProposalSync(req types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
app.mtx.Lock()
defer app.mtx.Unlock()
res := app.Application.ProcessProposal(req)
return &res, nil
}
//-------------------------------------------------------
func (app *localClient) callback(req *types.Request, res *types.Response) *ReqRes {

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
// Code generated by mockery. DO NOT EDIT.
package mocks
@@ -614,6 +614,45 @@ func (_m *Client) PrepareProposalSync(_a0 types.RequestPrepareProposal) (*types.
return r0, r1
}
// ProcessProposalAsync provides a mock function with given fields: _a0
func (_m *Client) ProcessProposalAsync(_a0 types.RequestProcessProposal) *abcicli.ReqRes {
ret := _m.Called(_a0)
var r0 *abcicli.ReqRes
if rf, ok := ret.Get(0).(func(types.RequestProcessProposal) *abcicli.ReqRes); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*abcicli.ReqRes)
}
}
return r0
}
// ProcessProposalSync provides a mock function with given fields: _a0
func (_m *Client) ProcessProposalSync(_a0 types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
ret := _m.Called(_a0)
var r0 *types.ResponseProcessProposal
if rf, ok := ret.Get(0).(func(types.RequestProcessProposal) *types.ResponseProcessProposal); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.ResponseProcessProposal)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(types.RequestProcessProposal) error); ok {
r1 = rf(_a0)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// QueryAsync provides a mock function with given fields: _a0
func (_m *Client) QueryAsync(_a0 types.RequestQuery) *abcicli.ReqRes {
ret := _m.Called(_a0)
@@ -688,45 +727,6 @@ func (_m *Client) SetLogger(_a0 log.Logger) {
_m.Called(_a0)
}
// SetOptionAsync provides a mock function with given fields: _a0
func (_m *Client) SetOptionAsync(_a0 types.RequestSetOption) *abcicli.ReqRes {
ret := _m.Called(_a0)
var r0 *abcicli.ReqRes
if rf, ok := ret.Get(0).(func(types.RequestSetOption) *abcicli.ReqRes); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*abcicli.ReqRes)
}
}
return r0
}
// SetOptionSync provides a mock function with given fields: _a0
func (_m *Client) SetOptionSync(_a0 types.RequestSetOption) (*types.ResponseSetOption, error) {
ret := _m.Called(_a0)
var r0 *types.ResponseSetOption
if rf, ok := ret.Get(0).(func(types.RequestSetOption) *types.ResponseSetOption); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.ResponseSetOption)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(types.RequestSetOption) error); ok {
r1 = rf(_a0)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// SetResponseCallback provides a mock function with given fields: _a0
func (_m *Client) SetResponseCallback(_a0 abcicli.Callback) {
_m.Called(_a0)

View File

@@ -231,10 +231,6 @@ func (cli *socketClient) InfoAsync(req types.RequestInfo) *ReqRes {
return cli.queueRequest(types.ToRequestInfo(req))
}
func (cli *socketClient) SetOptionAsync(req types.RequestSetOption) *ReqRes {
return cli.queueRequest(types.ToRequestSetOption(req))
}
func (cli *socketClient) DeliverTxAsync(req types.RequestDeliverTx) *ReqRes {
return cli.queueRequest(types.ToRequestDeliverTx(req))
}
@@ -283,6 +279,10 @@ func (cli *socketClient) PrepareProposalAsync(req types.RequestPrepareProposal)
return cli.queueRequest(types.ToRequestPrepareProposal(req))
}
func (cli *socketClient) ProcessProposalAsync(req types.RequestProcessProposal) *ReqRes {
return cli.queueRequest(types.ToRequestProcessProposal(req))
}
//----------------------------------------
func (cli *socketClient) FlushSync() error {
@@ -312,15 +312,6 @@ func (cli *socketClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, e
return reqres.Response.GetInfo(), cli.Error()
}
func (cli *socketClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
reqres := cli.queueRequest(types.ToRequestSetOption(req))
if err := cli.FlushSync(); err != nil {
return nil, err
}
return reqres.Response.GetSetOption(), cli.Error()
}
func (cli *socketClient) DeliverTxSync(req types.RequestDeliverTx) (*types.ResponseDeliverTx, error) {
reqres := cli.queueRequest(types.ToRequestDeliverTx(req))
if err := cli.FlushSync(); err != nil {
@@ -430,6 +421,15 @@ func (cli *socketClient) PrepareProposalSync(req types.RequestPrepareProposal) (
return reqres.Response.GetPrepareProposal(), cli.Error()
}
func (cli *socketClient) ProcessProposalSync(req types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
reqres := cli.queueRequest(types.ToRequestProcessProposal(req))
if err := cli.FlushSync(); err != nil {
return nil, err
}
return reqres.Response.GetProcessProposal(), cli.Error()
}
//----------------------------------------
func (cli *socketClient) queueRequest(req *types.Request) *ReqRes {
@@ -481,8 +481,6 @@ func resMatchesReq(req *types.Request, res *types.Response) (ok bool) {
_, ok = res.Value.(*types.Response_Flush)
case *types.Request_Info:
_, ok = res.Value.(*types.Response_Info)
case *types.Request_SetOption:
_, ok = res.Value.(*types.Response_SetOption)
case *types.Request_DeliverTx:
_, ok = res.Value.(*types.Response_DeliverTx)
case *types.Request_CheckTx:
@@ -507,6 +505,8 @@ func resMatchesReq(req *types.Request, res *types.Response) (ok bool) {
_, ok = res.Value.(*types.Response_OfferSnapshot)
case *types.Request_PrepareProposal:
_, ok = res.Value.(*types.Response_PrepareProposal)
case *types.Request_ProcessProposal:
_, ok = res.Value.(*types.Response_ProcessProposal)
}
return ok
}

View File

@@ -16,7 +16,6 @@ import (
abcicli "github.com/tendermint/tendermint/abci/client"
"github.com/tendermint/tendermint/abci/example/code"
"github.com/tendermint/tendermint/abci/example/counter"
"github.com/tendermint/tendermint/abci/example/kvstore"
"github.com/tendermint/tendermint/abci/server"
servertest "github.com/tendermint/tendermint/abci/tests/server"
@@ -44,9 +43,6 @@ var (
flagHeight int
flagProve bool
// counter
flagSerial bool
// kvstore
flagPersist string
)
@@ -58,9 +54,7 @@ var RootCmd = &cobra.Command{
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
switch cmd.Use {
case "counter", "kvstore": // for the examples apps, don't pre-run
return nil
case "version": // skip running for version command
case "kvstore", "version":
return nil
}
@@ -89,10 +83,11 @@ var RootCmd = &cobra.Command{
// Structure for data passed to print response.
type response struct {
// generic abci response
Data []byte
Code uint32
Info string
Log string
Data []byte
Code uint32
Info string
Log string
Status int32
Query *queryResponse
}
@@ -135,10 +130,6 @@ func addQueryFlags() {
"whether or not to return a merkle proof of the query result")
}
func addCounterFlags() {
counterCmd.PersistentFlags().BoolVarP(&flagSerial, "serial", "", false, "enforce incrementing (serial) transactions")
}
func addKVStoreFlags() {
kvstoreCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", "directory to use for a database")
}
@@ -148,18 +139,17 @@ func addCommands() {
RootCmd.AddCommand(consoleCmd)
RootCmd.AddCommand(echoCmd)
RootCmd.AddCommand(infoCmd)
RootCmd.AddCommand(setOptionCmd)
RootCmd.AddCommand(deliverTxCmd)
RootCmd.AddCommand(checkTxCmd)
RootCmd.AddCommand(commitCmd)
RootCmd.AddCommand(versionCmd)
RootCmd.AddCommand(testCmd)
RootCmd.AddCommand(prepareProposalCmd)
RootCmd.AddCommand(processProposalCmd)
addQueryFlags()
RootCmd.AddCommand(queryCmd)
// examples
addCounterFlags()
RootCmd.AddCommand(counterCmd)
addKVStoreFlags()
RootCmd.AddCommand(kvstoreCmd)
}
@@ -176,7 +166,6 @@ you'd like to run:
where example.file looks something like:
set_option serial on
check_tx 0x00
check_tx 0xff
deliver_tx 0x00
@@ -198,7 +187,7 @@ This command opens an interactive console for running any of the other commands
without opening a new connection each time
`,
Args: cobra.ExactArgs(0),
ValidArgs: []string{"echo", "info", "set_option", "deliver_tx", "check_tx", "commit", "query"},
ValidArgs: []string{"echo", "info", "deliver_tx", "check_tx", "prepare_proposal", "process_proposal", "commit", "query"},
RunE: cmdConsole,
}
@@ -216,13 +205,6 @@ var infoCmd = &cobra.Command{
Args: cobra.ExactArgs(0),
RunE: cmdInfo,
}
var setOptionCmd = &cobra.Command{
Use: "set_option",
Short: "set an option on the application",
Long: "set an option on the application",
Args: cobra.ExactArgs(2),
RunE: cmdSetOption,
}
var deliverTxCmd = &cobra.Command{
Use: "deliver_tx",
@@ -259,6 +241,22 @@ var versionCmd = &cobra.Command{
},
}
var prepareProposalCmd = &cobra.Command{
Use: "prepare_proposal",
Short: "prepare proposal",
Long: "prepare proposal",
Args: cobra.MinimumNArgs(0),
RunE: cmdPrepareProposal,
}
var processProposalCmd = &cobra.Command{
Use: "process_proposal",
Short: "process proposal",
Long: "process proposal",
Args: cobra.MinimumNArgs(0),
RunE: cmdProcessProposal,
}
var queryCmd = &cobra.Command{
Use: "query",
Short: "query the application state",
@@ -267,14 +265,6 @@ var queryCmd = &cobra.Command{
RunE: cmdQuery,
}
var counterCmd = &cobra.Command{
Use: "counter",
Short: "ABCI demo example",
Long: "ABCI demo example",
Args: cobra.ExactArgs(0),
RunE: cmdCounter,
}
var kvstoreCmd = &cobra.Command{
Use: "kvstore",
Short: "ABCI demo example",
@@ -324,7 +314,6 @@ func cmdTest(cmd *cobra.Command, args []string) error {
return compose(
[]func() error{
func() error { return servertest.InitChain(client) },
func() error { return servertest.SetOption(client, "serial", "on") },
func() error { return servertest.Commit(client, nil) },
func() error { return servertest.DeliverTx(client, []byte("abc"), code.CodeTypeBadNonce, nil) },
func() error { return servertest.Commit(client, nil) },
@@ -339,6 +328,16 @@ func cmdTest(cmd *cobra.Command, args []string) error {
return servertest.DeliverTx(client, []byte{0x00, 0x00, 0x06}, code.CodeTypeBadNonce, nil)
},
func() error { return servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5}) },
func() error {
return servertest.PrepareProposal(client, [][]byte{
{0x01},
}, [][]byte{{0x01}}, nil)
},
func() error {
return servertest.ProcessProposal(client, [][]byte{
{0x01},
}, types.ResponseProcessProposal_ACCEPT)
},
})
}
@@ -439,8 +438,10 @@ func muxOnCommands(cmd *cobra.Command, pArgs []string) error {
return cmdInfo(cmd, actualArgs)
case "query":
return cmdQuery(cmd, actualArgs)
case "set_option":
return cmdSetOption(cmd, actualArgs)
case "prepare_proposal":
return cmdPrepareProposal(cmd, actualArgs)
case "process_proposal":
return cmdProcessProposal(cmd, actualArgs)
default:
return cmdUnimplemented(cmd, pArgs)
}
@@ -464,7 +465,6 @@ func cmdUnimplemented(cmd *cobra.Command, args []string) error {
fmt.Printf("%s: %s\n", deliverTxCmd.Use, deliverTxCmd.Short)
fmt.Printf("%s: %s\n", queryCmd.Use, queryCmd.Short)
fmt.Printf("%s: %s\n", commitCmd.Use, commitCmd.Short)
fmt.Printf("%s: %s\n", setOptionCmd.Use, setOptionCmd.Short)
fmt.Println("Use \"[command] --help\" for more information about a command.")
return nil
@@ -504,25 +504,6 @@ func cmdInfo(cmd *cobra.Command, args []string) error {
const codeBad uint32 = 10
// Set an option on the application
func cmdSetOption(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
printResponse(cmd, args, response{
Code: codeBad,
Log: "want at least arguments of the form: <key> <value>",
})
return nil
}
key, val := args[0], args[1]
_, err := client.SetOptionSync(types.RequestSetOption{Key: key, Value: val})
if err != nil {
return err
}
printResponse(cmd, args, response{Log: "OK (SetOption doesn't return anything.)"}) // NOTE: Nothing to show...
return nil
}
// Append a new tx to application
func cmdDeliverTx(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
@@ -625,30 +606,59 @@ func cmdQuery(cmd *cobra.Command, args []string) error {
return nil
}
func cmdCounter(cmd *cobra.Command, args []string) error {
app := counter.NewApplication(flagSerial)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
func cmdPrepareProposal(cmd *cobra.Command, args []string) error {
txsBytesArray := make([][]byte, len(args))
// Start the listener
srv, err := server.NewServer(flagAddress, flagAbci, app)
for i, arg := range args {
txBytes, err := stringOrHexToBytes(arg)
if err != nil {
return err
}
txsBytesArray[i] = txBytes
}
res, err := client.PrepareProposalSync(types.RequestPrepareProposal{
Txs: txsBytesArray,
// kvstore has to have this parameter in order not to reject a tx as the default value is 0
MaxTxBytes: 65536,
})
if err != nil {
return err
}
srv.SetLogger(logger.With("module", "abci-server"))
if err := srv.Start(); err != nil {
resps := make([]response, 0, len(res.Txs))
for _, tx := range res.Txs {
resps = append(resps, response{
Code: code.CodeTypeOK,
Log: "Succeeded. Tx: " + string(tx),
})
}
printResponse(cmd, args, resps...)
return nil
}
func cmdProcessProposal(cmd *cobra.Command, args []string) error {
txsBytesArray := make([][]byte, len(args))
for i, arg := range args {
txBytes, err := stringOrHexToBytes(arg)
if err != nil {
return err
}
txsBytesArray[i] = txBytes
}
res, err := client.ProcessProposalSync(types.RequestProcessProposal{
Txs: txsBytesArray,
})
if err != nil {
return err
}
// Stop upon receiving SIGTERM or CTRL-C.
tmos.TrapSignal(logger, func() {
// Cleanup
if err := srv.Stop(); err != nil {
logger.Error("Error while stopping server", "err", err)
}
printResponse(cmd, args, response{
Status: int32(res.Status),
})
// Run forever.
select {}
return nil
}
func cmdKVStore(cmd *cobra.Command, args []string) error {
@@ -657,11 +667,14 @@ func cmdKVStore(cmd *cobra.Command, args []string) error {
// Create the application - in memory or persisted to disk
var app types.Application
if flagPersist == "" {
app = kvstore.NewApplication()
} else {
app = kvstore.NewPersistentKVStoreApplication(flagPersist)
app.(*kvstore.PersistentKVStoreApplication).SetLogger(logger.With("module", "kvstore"))
var err error
flagPersist, err = os.MkdirTemp("", "persistent_kvstore_tmp")
if err != nil {
return err
}
}
app = kvstore.NewPersistentKVStoreApplication(flagPersist)
app.(*kvstore.PersistentKVStoreApplication).SetLogger(logger.With("module", "kvstore"))
// Start the listener
srv, err := server.NewServer(flagAddress, flagAbci, app)
@@ -687,44 +700,49 @@ func cmdKVStore(cmd *cobra.Command, args []string) error {
//--------------------------------------------------------------------------------
func printResponse(cmd *cobra.Command, args []string, rsp response) {
func printResponse(cmd *cobra.Command, args []string, rsps ...response) {
if flagVerbose {
fmt.Println(">", cmd.Use, strings.Join(args, " "))
}
// Always print the status code.
if rsp.Code == types.CodeTypeOK {
fmt.Printf("-> code: OK\n")
} else {
fmt.Printf("-> code: %d\n", rsp.Code)
for _, rsp := range rsps {
// Always print the status code.
if rsp.Code == types.CodeTypeOK {
fmt.Printf("-> code: OK\n")
} else {
fmt.Printf("-> code: %d\n", rsp.Code)
}
}
if len(rsp.Data) != 0 {
// Do no print this line when using the commit command
// because the string comes out as gibberish
if cmd.Use != "commit" {
fmt.Printf("-> data: %s\n", rsp.Data)
if len(rsp.Data) != 0 {
// Do no print this line when using the commit command
// because the string comes out as gibberish
if cmd.Use != "commit" {
fmt.Printf("-> data: %s\n", rsp.Data)
}
fmt.Printf("-> data.hex: 0x%X\n", rsp.Data)
}
if rsp.Log != "" {
fmt.Printf("-> log: %s\n", rsp.Log)
}
if cmd.Use == "process_proposal" {
fmt.Printf("-> status: %s\n", types.ResponseProcessProposal_ProposalStatus_name[rsp.Status])
}
fmt.Printf("-> data.hex: 0x%X\n", rsp.Data)
}
if rsp.Log != "" {
fmt.Printf("-> log: %s\n", rsp.Log)
}
if rsp.Query != nil {
fmt.Printf("-> height: %d\n", rsp.Query.Height)
if rsp.Query.Key != nil {
fmt.Printf("-> key: %s\n", rsp.Query.Key)
fmt.Printf("-> key.hex: %X\n", rsp.Query.Key)
}
if rsp.Query.Value != nil {
fmt.Printf("-> value: %s\n", rsp.Query.Value)
fmt.Printf("-> value.hex: %X\n", rsp.Query.Value)
}
if rsp.Query.ProofOps != nil {
fmt.Printf("-> proof: %#v\n", rsp.Query.ProofOps)
if rsp.Query != nil {
fmt.Printf("-> height: %d\n", rsp.Query.Height)
if rsp.Query.Key != nil {
fmt.Printf("-> key: %s\n", rsp.Query.Key)
fmt.Printf("-> key.hex: %X\n", rsp.Query.Key)
}
if rsp.Query.Value != nil {
fmt.Printf("-> value: %s\n", rsp.Query.Value)
fmt.Printf("-> value.hex: %X\n", rsp.Query.Value)
}
if rsp.Query.ProofOps != nil {
fmt.Printf("-> proof: %#v\n", rsp.Query.ProofOps)
}
}
}
}

View File

@@ -7,4 +7,5 @@ const (
CodeTypeBadNonce uint32 = 2
CodeTypeUnauthorized uint32 = 3
CodeTypeUnknownError uint32 = 4
CodeTypeExecuted uint32 = 5
)

View File

@@ -1,103 +0,0 @@
package counter
import (
"encoding/binary"
"fmt"
"github.com/tendermint/tendermint/abci/example/code"
"github.com/tendermint/tendermint/abci/types"
)
type Application struct {
types.BaseApplication
hashCount int
txCount int
serial bool
}
func NewApplication(serial bool) *Application {
return &Application{serial: serial}
}
func (app *Application) Info(req types.RequestInfo) types.ResponseInfo {
return types.ResponseInfo{Data: fmt.Sprintf("{\"hashes\":%v,\"txs\":%v}", app.hashCount, app.txCount)}
}
func (app *Application) SetOption(req types.RequestSetOption) types.ResponseSetOption {
key, value := req.Key, req.Value
if key == "serial" && value == "on" {
app.serial = true
} else {
/*
TODO Panic and have the ABCI server pass an exception.
The client can call SetOptionSync() and get an `error`.
return types.ResponseSetOption{
Error: fmt.Sprintf("Unknown key (%s) or value (%s)", key, value),
}
*/
return types.ResponseSetOption{}
}
return types.ResponseSetOption{}
}
func (app *Application) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx {
if app.serial {
if len(req.Tx) > 8 {
return types.ResponseDeliverTx{
Code: code.CodeTypeEncodingError,
Log: fmt.Sprintf("Max tx size is 8 bytes, got %d", len(req.Tx))}
}
tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(req.Tx):], req.Tx)
txValue := binary.BigEndian.Uint64(tx8)
if txValue != uint64(app.txCount) {
return types.ResponseDeliverTx{
Code: code.CodeTypeBadNonce,
Log: fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.txCount, txValue)}
}
}
app.txCount++
return types.ResponseDeliverTx{Code: code.CodeTypeOK}
}
func (app *Application) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx {
if app.serial {
if len(req.Tx) > 8 {
return types.ResponseCheckTx{
Code: code.CodeTypeEncodingError,
Log: fmt.Sprintf("Max tx size is 8 bytes, got %d", len(req.Tx))}
}
tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(req.Tx):], req.Tx)
txValue := binary.BigEndian.Uint64(tx8)
if txValue < uint64(app.txCount) {
return types.ResponseCheckTx{
Code: code.CodeTypeBadNonce,
Log: fmt.Sprintf("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue)}
}
}
return types.ResponseCheckTx{Code: code.CodeTypeOK}
}
func (app *Application) Commit() (resp types.ResponseCommit) {
app.hashCount++
if app.txCount == 0 {
return types.ResponseCommit{}
}
hash := make([]byte, 8)
binary.BigEndian.PutUint64(hash, uint64(app.txCount))
return types.ResponseCommit{Data: hash}
}
func (app *Application) Query(reqQuery types.RequestQuery) types.ResponseQuery {
switch reqQuery.Path {
case "hash":
return types.ResponseQuery{Value: []byte(fmt.Sprintf("%v", app.hashCount))}
case "tx":
return types.ResponseQuery{Value: []byte(fmt.Sprintf("%v", app.txCount))}
default:
return types.ResponseQuery{Log: fmt.Sprintf("Invalid query path. Expected hash or tx, got %v", reqQuery.Path)}
}
}

View File

@@ -68,6 +68,7 @@ type Application struct {
state State
RetainBlocks int64 // blocks to retain after commit (via ResponseCommit.RetainHeight)
txToRemove map[string]struct{}
}
func NewApplication() *Application {
@@ -87,15 +88,19 @@ func (app *Application) Info(req types.RequestInfo) (resInfo types.ResponseInfo)
// tx is either "key=value" or just arbitrary bytes
func (app *Application) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx {
var key, value []byte
if isReplacedTx(req.Tx) {
app.txToRemove[string(req.Tx)] = struct{}{}
}
var key, value string
parts := bytes.Split(req.Tx, []byte("="))
if len(parts) == 2 {
key, value = parts[0], parts[1]
key, value = string(parts[0]), string(parts[1])
} else {
key, value = req.Tx, req.Tx
key, value = string(req.Tx), string(req.Tx)
}
err := app.state.db.Set(prefixKey(key), value)
err := app.state.db.Set(prefixKey([]byte(key)), []byte(value))
if err != nil {
panic(err)
}
@@ -105,10 +110,10 @@ func (app *Application) DeliverTx(req types.RequestDeliverTx) types.ResponseDeli
{
Type: "app",
Attributes: []types.EventAttribute{
{Key: []byte("creator"), Value: []byte("Cosmoshi Netowoko"), Index: true},
{Key: []byte("key"), Value: key, Index: true},
{Key: []byte("index_key"), Value: []byte("index is working"), Index: true},
{Key: []byte("noindex_key"), Value: []byte("index is working"), Index: false},
{Key: "creator", Value: "Cosmoshi Netowoko", Index: true},
{Key: "key", Value: key, Index: true},
{Key: "index_key", Value: "index is working", Index: true},
{Key: "noindex_key", Value: "index is working", Index: false},
},
},
}
@@ -117,6 +122,11 @@ func (app *Application) DeliverTx(req types.RequestDeliverTx) types.ResponseDeli
}
func (app *Application) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx {
if req.Type == types.CheckTxType_Recheck {
if _, ok := app.txToRemove[string(req.Tx)]; ok {
return types.ResponseCheckTx{Code: code.CodeTypeExecuted, GasWanted: 1}
}
}
return types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}
}
@@ -126,6 +136,8 @@ func (app *Application) Commit() types.ResponseCommit {
binary.PutVarint(appHash, app.state.Size)
app.state.AppHash = appHash
app.state.Height++
// empty out the set of transactions to remove via rechecktx
saveState(app.state)
resp := types.ResponseCommit{Data: appHash}
@@ -170,3 +182,18 @@ func (app *Application) Query(reqQuery types.RequestQuery) (resQuery types.Respo
return resQuery
}
func (app *Application) BeginBlock(req types.RequestBeginBlock) types.ResponseBeginBlock {
app.txToRemove = map[string]struct{}{}
return types.ResponseBeginBlock{}
}
func (app *Application) ProcessProposal(
req types.RequestProcessProposal) types.ResponseProcessProposal {
for _, tx := range req.Txs {
if len(tx) == 0 {
return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}
}
}
return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_ACCEPT}
}

View File

@@ -2,7 +2,7 @@ package kvstore
import (
"fmt"
"io/ioutil"
"os"
"sort"
"testing"
@@ -71,7 +71,7 @@ func TestKVStoreKV(t *testing.T) {
}
func TestPersistentKVStoreKV(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
dir, err := os.MkdirTemp("/tmp", "abci-kvstore-test") // TODO
if err != nil {
t.Fatal(err)
}
@@ -87,7 +87,7 @@ func TestPersistentKVStoreKV(t *testing.T) {
}
func TestPersistentKVStoreInfo(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
dir, err := os.MkdirTemp("/tmp", "abci-kvstore-test") // TODO
if err != nil {
t.Fatal(err)
}
@@ -119,7 +119,7 @@ func TestPersistentKVStoreInfo(t *testing.T) {
// add a validator, remove a validator, update a validator
func TestValUpdates(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
dir, err := os.MkdirTemp("/tmp", "abci-kvstore-test") // TODO
if err != nil {
t.Fatal(err)
}
@@ -162,7 +162,7 @@ func TestValUpdates(t *testing.T) {
makeApplyBlock(t, kvstore, 2, diff, tx1, tx2, tx3)
vals1 = append(vals[:nInit-2], vals[nInit+1]) // nolint: gocritic
vals1 = append(vals[:nInit-2], vals[nInit+1]) //nolint: gocritic
vals2 = kvstore.Validators()
valsEqual(t, vals1, vals2)

View File

@@ -45,7 +45,10 @@ func NewPersistentKVStoreApplication(dbDir string) *PersistentKVStoreApplication
state := loadState(db)
return &PersistentKVStoreApplication{
app: &Application{state: state},
app: &Application{
state: state,
txToRemove: map[string]struct{}{},
},
valAddrToPubKeyMap: make(map[string]pc.PublicKey),
logger: log.NewNopLogger(),
}
@@ -62,10 +65,6 @@ func (app *PersistentKVStoreApplication) Info(req types.RequestInfo) types.Respo
return res
}
func (app *PersistentKVStoreApplication) SetOption(req types.RequestSetOption) types.ResponseSetOption {
return app.app.SetOption(req)
}
// tx is either "val:pubkey!power" or "key=value" or just arbitrary bytes
func (app *PersistentKVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx {
// if it starts with "val:", update the validator set
@@ -130,7 +129,7 @@ func (app *PersistentKVStoreApplication) BeginBlock(req types.RequestBeginBlock)
// Punish validators who committed equivocation.
for _, ev := range req.ByzantineValidators {
if ev.Type == types.EvidenceType_DUPLICATE_VOTE {
if ev.Type == types.MisbehaviorType_DUPLICATE_VOTE {
addr := string(ev.Validator.Address)
if pubKey, ok := app.valAddrToPubKeyMap[addr]; ok {
app.updateValidator(types.ValidatorUpdate{
@@ -146,7 +145,7 @@ func (app *PersistentKVStoreApplication) BeginBlock(req types.RequestBeginBlock)
}
}
return types.ResponseBeginBlock{}
return app.app.BeginBlock(req)
}
// Update the validator set
@@ -176,7 +175,17 @@ func (app *PersistentKVStoreApplication) ApplySnapshotChunk(
func (app *PersistentKVStoreApplication) PrepareProposal(
req types.RequestPrepareProposal) types.ResponsePrepareProposal {
return types.ResponsePrepareProposal{TxRecords: app.substPrepareTx(req.Txs, req.MaxTxBytes)}
return types.ResponsePrepareProposal{Txs: app.substPrepareTx(req.Txs, req.MaxTxBytes)}
}
func (app *PersistentKVStoreApplication) ProcessProposal(
req types.RequestProcessProposal) types.ResponseProcessProposal {
for _, tx := range req.Txs {
if len(tx) == 0 || isPrepareTx(tx) {
return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}
}
}
return types.ResponseProcessProposal{Status: types.ResponseProcessProposal_ACCEPT}
}
//---------------------------------------------
@@ -296,10 +305,15 @@ func (app *PersistentKVStoreApplication) updateValidator(v types.ValidatorUpdate
// -----------------------------
const PreparePrefix = "prepare"
const (
PreparePrefix = "prepare"
ReplacePrefix = "replace"
)
func isPrepareTx(tx []byte) bool {
return bytes.HasPrefix(tx, []byte(PreparePrefix))
func isPrepareTx(tx []byte) bool { return bytes.HasPrefix(tx, []byte(PreparePrefix)) }
func isReplacedTx(tx []byte) bool {
return bytes.HasPrefix(tx, []byte(ReplacePrefix))
}
// execPrepareTx is noop. tx data is considered as placeholder
@@ -311,32 +325,19 @@ func (app *PersistentKVStoreApplication) execPrepareTx(tx []byte) types.Response
// substPrepareTx substitutes all the transactions prefixed with 'prepare' in the
// proposal for transactions with the prefix stripped.
// It marks all of the original transactions as 'REMOVED' so that
// Tendermint will remove them from its mempool.
func (app *PersistentKVStoreApplication) substPrepareTx(blockData [][]byte, maxTxBytes int64) []*types.TxRecord {
trs := make([]*types.TxRecord, 0, len(blockData))
var removed []*types.TxRecord
func (app *PersistentKVStoreApplication) substPrepareTx(blockData [][]byte, maxTxBytes int64) [][]byte {
txs := make([][]byte, 0, len(blockData))
var totalBytes int64
for _, tx := range blockData {
txMod := tx
action := types.TxRecord_UNMODIFIED
if isPrepareTx(tx) {
removed = append(removed, &types.TxRecord{
Tx: tx,
Action: types.TxRecord_REMOVED,
})
txMod = bytes.TrimPrefix(tx, []byte(PreparePrefix))
action = types.TxRecord_ADDED
txMod = bytes.Replace(tx, []byte(PreparePrefix), []byte(ReplacePrefix), 1)
}
totalBytes += int64(len(txMod))
if totalBytes > maxTxBytes {
break
}
trs = append(trs, &types.TxRecord{
Tx: txMod,
Action: action,
})
txs = append(txs, txMod)
}
return append(trs, removed...)
return txs
}

View File

@@ -2,9 +2,8 @@
Package server is used to start a new ABCI server.
It contains two server implementation:
* gRPC server
* socket server
- gRPC server
- socket server
*/
package server

View File

@@ -200,9 +200,6 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types
case *types.Request_Info:
res := s.app.Info(*r.Info)
responses <- types.ToResponseInfo(res)
case *types.Request_SetOption:
res := s.app.SetOption(*r.SetOption)
responses <- types.ToResponseSetOption(res)
case *types.Request_DeliverTx:
res := s.app.DeliverTx(*r.DeliverTx)
responses <- types.ToResponseDeliverTx(res)
@@ -233,6 +230,9 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types
case *types.Request_PrepareProposal:
res := s.app.PrepareProposal(*r.PrepareProposal)
responses <- types.ToResponsePrepareProposal(res)
case *types.Request_ProcessProposal:
res := s.app.ProcessProposal(*r.ProcessProposal)
responses <- types.ToResponseProcessProposal(res)
case *types.Request_LoadSnapshotChunk:
res := s.app.LoadSnapshotChunk(*r.LoadSnapshotChunk)
responses <- types.ToResponseLoadSnapshotChunk(res)

View File

@@ -19,9 +19,12 @@ func TestClientServerNoAddrPrefix(t *testing.T) {
assert.NoError(t, err, "expected no error on NewServer")
err = server.Start()
assert.NoError(t, err, "expected no error on server.Start")
defer func() { _ = server.Stop() }()
client, err := abciclient.NewClient(addr, transport, true)
assert.NoError(t, err, "expected no error on NewClient")
err = client.Start()
assert.NoError(t, err, "expected no error on client.Start")
_ = client.Stop()
}

View File

@@ -29,17 +29,6 @@ func InitChain(client abcicli.Client) error {
return nil
}
func SetOption(client abcicli.Client, key, value string) error {
_, err := client.SetOptionSync(types.RequestSetOption{Key: key, Value: value})
if err != nil {
fmt.Println("Failed test: SetOption")
fmt.Printf("error while setting %v=%v: \nerror: %v\n", key, value, err)
return err
}
fmt.Println("Passed test: SetOption")
return nil
}
func Commit(client abcicli.Client, hashExp []byte) error {
res, err := client.CommitSync()
data := res.Data
@@ -76,6 +65,32 @@ func DeliverTx(client abcicli.Client, txBytes []byte, codeExp uint32, dataExp []
return nil
}
func PrepareProposal(client abcicli.Client, txBytes [][]byte, txExpected [][]byte, dataExp []byte) error {
res, _ := client.PrepareProposalSync(types.RequestPrepareProposal{Txs: txBytes})
for i, tx := range res.Txs {
if !bytes.Equal(tx, txExpected[i]) {
fmt.Println("Failed test: PrepareProposal")
fmt.Printf("PrepareProposal transaction was unexpected. Got %x expected %x.",
tx, txExpected[i])
return errors.New("PrepareProposal error")
}
}
fmt.Println("Passed test: PrepareProposal")
return nil
}
func ProcessProposal(client abcicli.Client, txBytes [][]byte, statusExp types.ResponseProcessProposal_ProposalStatus) error {
res, _ := client.ProcessProposalSync(types.RequestProcessProposal{Txs: txBytes})
if res.Status != statusExp {
fmt.Println("Failed test: ProcessProposal")
fmt.Printf("ProcessProposal response status was unexpected. Got %v expected %v.",
res.Status, statusExp)
return errors.New("ProcessProposal error")
}
fmt.Println("Passed test: ProcessProposal")
return nil
}
func CheckTx(client abcicli.Client, txBytes []byte, codeExp uint32, dataExp []byte) error {
res, _ := client.CheckTxSync(types.RequestCheckTx{Tx: txBytes})
code, data, log := res.Code, res.Data, res.Log

View File

@@ -1,78 +0,0 @@
package main
import (
"bytes"
"fmt"
"os"
abcicli "github.com/tendermint/tendermint/abci/client"
"github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
)
func startClient(abciType string) abcicli.Client {
// Start client
client, err := abcicli.NewClient("tcp://127.0.0.1:26658", abciType, true)
if err != nil {
panic(err.Error())
}
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
client.SetLogger(logger.With("module", "abcicli"))
if err := client.Start(); err != nil {
panicf("connecting to abci_app: %v", err.Error())
}
return client
}
func setOption(client abcicli.Client, key, value string) {
_, err := client.SetOptionSync(types.RequestSetOption{Key: key, Value: value})
if err != nil {
panicf("setting %v=%v: \nerr: %v", key, value, err)
}
}
func commit(client abcicli.Client, hashExp []byte) {
res, err := client.CommitSync()
if err != nil {
panicf("client error: %v", err)
}
if !bytes.Equal(res.Data, hashExp) {
panicf("Commit hash was unexpected. Got %X expected %X", res.Data, hashExp)
}
}
func deliverTx(client abcicli.Client, txBytes []byte, codeExp uint32, dataExp []byte) {
res, err := client.DeliverTxSync(types.RequestDeliverTx{Tx: txBytes})
if err != nil {
panicf("client error: %v", err)
}
if res.Code != codeExp {
panicf("DeliverTx response code was unexpected. Got %v expected %v. Log: %v", res.Code, codeExp, res.Log)
}
if !bytes.Equal(res.Data, dataExp) {
panicf("DeliverTx response data was unexpected. Got %X expected %X", res.Data, dataExp)
}
}
/*func checkTx(client abcicli.Client, txBytes []byte, codeExp uint32, dataExp []byte) {
res, err := client.CheckTxSync(txBytes)
if err != nil {
panicf("client error: %v", err)
}
if res.IsErr() {
panicf("checking tx %X: %v\nlog: %v", txBytes, res.Log)
}
if res.Code != codeExp {
panicf("CheckTx response code was unexpected. Got %v expected %v. Log: %v",
res.Code, codeExp, res.Log)
}
if !bytes.Equal(res.Data, dataExp) {
panicf("CheckTx response data was unexpected. Got %X expected %X",
res.Data, dataExp)
}
}*/
func panicf(format string, a ...interface{}) {
panic(fmt.Sprintf(format, a...))
}

View File

@@ -1,95 +0,0 @@
package main
import (
"fmt"
"log"
"os"
"os/exec"
"time"
"github.com/tendermint/tendermint/abci/example/code"
"github.com/tendermint/tendermint/abci/types"
)
var abciType string
func init() {
abciType = os.Getenv("ABCI")
if abciType == "" {
abciType = "socket"
}
}
func main() {
testCounter()
}
const (
maxABCIConnectTries = 10
)
func ensureABCIIsUp(typ string, n int) error {
var err error
cmdString := "abci-cli echo hello"
if typ == "grpc" {
cmdString = "abci-cli --abci grpc echo hello"
}
for i := 0; i < n; i++ {
cmd := exec.Command("bash", "-c", cmdString)
_, err = cmd.CombinedOutput()
if err == nil {
break
}
<-time.After(500 * time.Millisecond)
}
return err
}
func testCounter() {
abciApp := os.Getenv("ABCI_APP")
if abciApp == "" {
panic("No ABCI_APP specified")
}
fmt.Printf("Running %s test with abci=%s\n", abciApp, abciType)
subCommand := fmt.Sprintf("abci-cli %s", abciApp)
cmd := exec.Command("bash", "-c", subCommand)
cmd.Stdout = os.Stdout
if err := cmd.Start(); err != nil {
log.Fatalf("starting %q err: %v", abciApp, err)
}
defer func() {
if err := cmd.Process.Kill(); err != nil {
log.Printf("error on process kill: %v", err)
}
if err := cmd.Wait(); err != nil {
log.Printf("error while waiting for cmd to exit: %v", err)
}
}()
if err := ensureABCIIsUp(abciType, maxABCIConnectTries); err != nil {
log.Fatalf("echo failed: %v", err) //nolint:gocritic
}
client := startClient(abciType)
defer func() {
if err := client.Stop(); err != nil {
log.Printf("error trying client stop: %v", err)
}
}()
setOption(client, "serial", "on")
commit(client, nil)
deliverTx(client, []byte("abc"), code.CodeTypeBadNonce, nil)
commit(client, nil)
deliverTx(client, []byte{0x00}, types.CodeTypeOK, nil)
commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 1})
deliverTx(client, []byte{0x00}, code.CodeTypeBadNonce, nil)
deliverTx(client, []byte{0x01}, types.CodeTypeOK, nil)
deliverTx(client, []byte{0x00, 0x02}, types.CodeTypeOK, nil)
deliverTx(client, []byte{0x00, 0x03}, types.CodeTypeOK, nil)
deliverTx(client, []byte{0x00, 0x00, 0x04}, types.CodeTypeOK, nil)
deliverTx(client, []byte{0x00, 0x00, 0x06}, code.CodeTypeBadNonce, nil)
commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5})
}

View File

@@ -1,28 +0,0 @@
#! /bin/bash
set -e
# These tests spawn the counter app and server by execing the ABCI_APP command and run some simple client tests against it
# Get the directory of where this script is.
export PATH="$GOBIN:$PATH"
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
# Change into that dir because we expect that.
cd "$DIR"
echo "RUN COUNTER OVER SOCKET"
# test golang counter
ABCI_APP="counter" go run -mod=readonly ./*.go
echo "----------------------"
echo "RUN COUNTER OVER GRPC"
# test golang counter via grpc
ABCI_APP="counter --abci=grpc" ABCI="grpc" go run -mod=readonly ./*.go
echo "----------------------"
# test nodejs counter
# TODO: fix node app
#ABCI_APP="node $GOPATH/src/github.com/tendermint/js-abci/example/app.js" go test -test.run TestCounter

View File

@@ -1,5 +1,7 @@
echo hello
info
prepare_proposal "abc"
process_proposal "abc"
commit
deliver_tx "abc"
info
@@ -8,3 +10,9 @@ query "abc"
deliver_tx "def=xyz"
commit
query "def"
prepare_proposal "preparedef"
process_proposal "replacedef"
process_proposal "preparedef"
prepare_proposal
process_proposal
commit

View File

@@ -8,6 +8,14 @@
-> data: {"size":0}
-> data.hex: 0x7B2273697A65223A307D
> prepare_proposal "abc"
-> code: OK
-> log: Succeeded. Tx: abc
> process_proposal "abc"
-> code: OK
-> status: ACCEPT
> commit
-> code: OK
-> data.hex: 0x0000000000000000
@@ -49,3 +57,25 @@
-> value: xyz
-> value.hex: 78797A
> prepare_proposal "preparedef"
-> code: OK
-> log: Succeeded. Tx: replacedef
> process_proposal "replacedef"
-> code: OK
-> status: ACCEPT
> process_proposal "preparedef"
-> code: OK
-> status: REJECT
> prepare_proposal
> process_proposal
-> code: OK
-> status: ACCEPT
> commit
-> code: OK
-> data.hex: 0x0400000000000000

View File

@@ -1,4 +1,3 @@
set_option serial on
check_tx 0x00
check_tx 0xff
deliver_tx 0x00

View File

@@ -1,7 +1,3 @@
> set_option serial on
-> code: OK
-> log: OK (SetOption doesn't return anything.)
> check_tx 0x00
-> code: OK
@@ -12,18 +8,16 @@
-> code: OK
> check_tx 0x00
-> code: 2
-> log: Invalid nonce. Expected >= 1, got 0
-> code: OK
> deliver_tx 0x01
-> code: OK
> deliver_tx 0x04
-> code: 2
-> log: Invalid nonce. Expected 2, got 4
-> code: OK
> info
-> code: OK
-> data: {"hashes":0,"txs":2}
-> data.hex: 0x7B22686173686573223A302C22747873223A327D
-> data: {"size":3}
-> data.hex: 0x7B2273697A65223A337D

View File

@@ -30,6 +30,8 @@ function testExample() {
cat "${INPUT}.out.new"
echo "Expected:"
cat "${INPUT}.out"
echo "Diff:"
diff "${INPUT}.out" "${INPUT}.out.new"
exit 1
fi
@@ -37,7 +39,7 @@ function testExample() {
}
testExample 1 tests/test_cli/ex1.abci abci-cli kvstore
testExample 2 tests/test_cli/ex2.abci abci-cli counter
testExample 2 tests/test_cli/ex2.abci abci-cli kvstore
echo ""
echo "PASS"

View File

@@ -4,16 +4,16 @@ import (
context "golang.org/x/net/context"
)
//go:generate mockery --case underscore --name Application
//go:generate ../../scripts/mockery_generate.sh Application
// Application is an interface that enables any finite, deterministic state machine
// to be driven by a blockchain-based replication engine via the ABCI.
// All methods take a RequestXxx argument and return a ResponseXxx argument,
// except CheckTx/DeliverTx, which take `tx []byte`, and `Commit`, which takes nothing.
type Application interface {
// Info/Query Connection
Info(RequestInfo) ResponseInfo // Return application info
SetOption(RequestSetOption) ResponseSetOption // Set application option
Query(RequestQuery) ResponseQuery // Query for state
Info(RequestInfo) ResponseInfo // Return application info
Query(RequestQuery) ResponseQuery // Query for state
// Mempool Connection
CheckTx(RequestCheckTx) ResponseCheckTx // Validate a tx for the mempool
@@ -21,6 +21,7 @@ type Application interface {
// Consensus Connection
InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain w validators/other info from TendermintCore
PrepareProposal(RequestPrepareProposal) ResponsePrepareProposal
ProcessProposal(RequestProcessProposal) ResponseProcessProposal
BeginBlock(RequestBeginBlock) ResponseBeginBlock // Signals the beginning of a block
DeliverTx(RequestDeliverTx) ResponseDeliverTx // Deliver a tx for full processing
EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set
@@ -49,10 +50,6 @@ func (BaseApplication) Info(req RequestInfo) ResponseInfo {
return ResponseInfo{}
}
func (BaseApplication) SetOption(req RequestSetOption) ResponseSetOption {
return ResponseSetOption{}
}
func (BaseApplication) DeliverTx(req RequestDeliverTx) ResponseDeliverTx {
return ResponseDeliverTx{Code: CodeTypeOK}
}
@@ -98,19 +95,21 @@ func (BaseApplication) ApplySnapshotChunk(req RequestApplySnapshotChunk) Respons
}
func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepareProposal {
trs := make([]*TxRecord, 0, len(req.Txs))
txs := make([][]byte, 0, len(req.Txs))
var totalBytes int64
for _, tx := range req.Txs {
totalBytes += int64(len(tx))
if totalBytes > req.MaxTxBytes {
break
}
trs = append(trs, &TxRecord{
Action: TxRecord_UNMODIFIED,
Tx: tx,
})
txs = append(txs, tx)
}
return ResponsePrepareProposal{TxRecords: trs}
return ResponsePrepareProposal{Txs: txs}
}
func (BaseApplication) ProcessProposal(req RequestProcessProposal) ResponseProcessProposal {
return ResponseProcessProposal{
Status: ResponseProcessProposal_ACCEPT}
}
//-------------------------------------------------------
@@ -137,11 +136,6 @@ func (app *GRPCApplication) Info(ctx context.Context, req *RequestInfo) (*Respon
return &res, nil
}
func (app *GRPCApplication) SetOption(ctx context.Context, req *RequestSetOption) (*ResponseSetOption, error) {
res := app.app.SetOption(*req)
return &res, nil
}
func (app *GRPCApplication) DeliverTx(ctx context.Context, req *RequestDeliverTx) (*ResponseDeliverTx, error) {
res := app.app.DeliverTx(*req)
return &res, nil
@@ -206,3 +200,9 @@ func (app *GRPCApplication) PrepareProposal(
res := app.app.PrepareProposal(*req)
return &res, nil
}
func (app *GRPCApplication) ProcessProposal(
ctx context.Context, req *RequestProcessProposal) (*ResponseProcessProposal, error) {
res := app.app.ProcessProposal(*req)
return &res, nil
}

View File

@@ -1,11 +1,10 @@
package types
import (
"bufio"
"encoding/binary"
"io"
"github.com/gogo/protobuf/proto"
"github.com/cosmos/gogoproto/proto"
"github.com/tendermint/tendermint/libs/protoio"
)
const (
@@ -14,57 +13,19 @@ const (
// WriteMessage writes a varint length-delimited protobuf message.
func WriteMessage(msg proto.Message, w io.Writer) error {
bz, err := proto.Marshal(msg)
protoWriter := protoio.NewDelimitedWriter(w)
_, err := protoWriter.WriteMsg(msg)
if err != nil {
return err
}
return encodeByteSlice(w, bz)
return nil
}
// ReadMessage reads a varint length-delimited protobuf message.
func ReadMessage(r io.Reader, msg proto.Message) error {
return readProtoMsg(r, msg, maxMsgSize)
}
func readProtoMsg(r io.Reader, msg proto.Message, maxSize int) error {
// binary.ReadVarint takes an io.ByteReader, eg. a bufio.Reader
reader, ok := r.(*bufio.Reader)
if !ok {
reader = bufio.NewReader(r)
}
length64, err := binary.ReadVarint(reader)
if err != nil {
return err
}
length := int(length64)
if length < 0 || length > maxSize {
return io.ErrShortBuffer
}
buf := make([]byte, length)
if _, err := io.ReadFull(reader, buf); err != nil {
return err
}
return proto.Unmarshal(buf, msg)
}
//-----------------------------------------------------------------------
// NOTE: we copied wire.EncodeByteSlice from go-wire rather than keep
// go-wire as a dep
func encodeByteSlice(w io.Writer, bz []byte) (err error) {
err = encodeVarint(w, int64(len(bz)))
if err != nil {
return
}
_, err = w.Write(bz)
return
}
func encodeVarint(w io.Writer, i int64) (err error) {
var buf [10]byte
n := binary.PutVarint(buf[:], i)
_, err = w.Write(buf[0:n])
return
_, err := protoio.NewDelimitedReader(r, maxMsgSize).ReadMsg(msg)
return err
}
//----------------------------------------
@@ -87,12 +48,6 @@ func ToRequestInfo(req RequestInfo) *Request {
}
}
func ToRequestSetOption(req RequestSetOption) *Request {
return &Request{
Value: &Request_SetOption{&req},
}
}
func ToRequestDeliverTx(req RequestDeliverTx) *Request {
return &Request{
Value: &Request_DeliverTx{&req},
@@ -165,6 +120,12 @@ func ToRequestPrepareProposal(req RequestPrepareProposal) *Request {
}
}
func ToRequestProcessProposal(req RequestProcessProposal) *Request {
return &Request{
Value: &Request_ProcessProposal{&req},
}
}
//----------------------------------------
func ToResponseException(errStr string) *Response {
@@ -191,12 +152,6 @@ func ToResponseInfo(res ResponseInfo) *Response {
}
}
func ToResponseSetOption(res ResponseSetOption) *Response {
return &Response{
Value: &Response_SetOption{&res},
}
}
func ToResponseDeliverTx(res ResponseDeliverTx) *Response {
return &Response{
Value: &Response_DeliverTx{&res},
@@ -268,3 +223,9 @@ func ToResponsePrepareProposal(res ResponsePrepareProposal) *Response {
Value: &Response_PrepareProposal{&res},
}
}
func ToResponseProcessProposal(res ResponseProcessProposal) *Response {
return &Response{
Value: &Response_ProcessProposal{&res},
}
}

View File

@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/assert"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
@@ -25,7 +25,7 @@ func TestMarshalJSON(t *testing.T) {
{
Type: "testEvent",
Attributes: []EventAttribute{
{Key: []byte("pho"), Value: []byte("bo")},
{Key: "pho", Value: "bo"},
},
},
},
@@ -92,7 +92,7 @@ func TestWriteReadMessage2(t *testing.T) {
{
Type: "testEvent",
Attributes: []EventAttribute{
{Key: []byte("abc"), Value: []byte("def")},
{Key: "abc", Value: "def"},
},
},
},

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
// Code generated by mockery. DO NOT EDIT.
package mocks
@@ -180,6 +180,20 @@ func (_m *Application) PrepareProposal(_a0 types.RequestPrepareProposal) types.R
return r0
}
// ProcessProposal provides a mock function with given fields: _a0
func (_m *Application) ProcessProposal(_a0 types.RequestProcessProposal) types.ResponseProcessProposal {
ret := _m.Called(_a0)
var r0 types.ResponseProcessProposal
if rf, ok := ret.Get(0).(func(types.RequestProcessProposal) types.ResponseProcessProposal); ok {
r0 = rf(_a0)
} else {
r0 = ret.Get(0).(types.ResponseProcessProposal)
}
return r0
}
// Query provides a mock function with given fields: _a0
func (_m *Application) Query(_a0 types.RequestQuery) types.ResponseQuery {
ret := _m.Called(_a0)
@@ -194,20 +208,6 @@ func (_m *Application) Query(_a0 types.RequestQuery) types.ResponseQuery {
return r0
}
// SetOption provides a mock function with given fields: _a0
func (_m *Application) SetOption(_a0 types.RequestSetOption) types.ResponseSetOption {
ret := _m.Called(_a0)
var r0 types.ResponseSetOption
if rf, ok := ret.Get(0).(func(types.RequestSetOption) types.ResponseSetOption); ok {
r0 = rf(_a0)
} else {
r0 = ret.Get(0).(types.ResponseSetOption)
}
return r0
}
type mockConstructorTestingTNewApplication interface {
mock.TestingT
Cleanup(func())

View File

@@ -84,6 +84,17 @@ func (m BaseMock) PrepareProposal(input types.RequestPrepareProposal) types.Resp
return ret
}
func (m BaseMock) ProcessProposal(input types.RequestProcessProposal) types.ResponseProcessProposal {
var ret types.ResponseProcessProposal
defer func() {
if r := recover(); r != nil {
ret = m.base.ProcessProposal(input)
}
}()
ret = m.Application.ProcessProposal(input)
return ret
}
// Commit the state and return the application Merkle root hash
func (m BaseMock) Commit() types.ResponseCommit {
var ret types.ResponseCommit

View File

@@ -4,7 +4,7 @@ import (
"bytes"
"encoding/json"
"github.com/gogo/protobuf/jsonpb"
"github.com/cosmos/gogoproto/jsonpb"
)
const (
@@ -41,6 +41,16 @@ func (r ResponseQuery) IsErr() bool {
return r.Code != CodeTypeOK
}
// IsAccepted returns true if Code is ACCEPT
func (r ResponseProcessProposal) IsAccepted() bool {
return r.Status == ResponseProcessProposal_ACCEPT
}
// IsStatusUnknown returns true if Code is UNKNOWN
func (r ResponseProcessProposal) IsStatusUnknown() bool {
return r.Status == ResponseProcessProposal_UNKNOWN
}
//---------------------------------------------------------------------------
// override JSON marshaling so we emit defaults (ie. disable omitempty)
@@ -52,16 +62,6 @@ var (
jsonpbUnmarshaller = jsonpb.Unmarshaler{}
)
func (r *ResponseSetOption) MarshalJSON() ([]byte, error) {
s, err := jsonpbMarshaller.MarshalToString(r)
return []byte(s), err
}
func (r *ResponseSetOption) UnmarshalJSON(b []byte) error {
reader := bytes.NewBuffer(b)
return jsonpbUnmarshaller.Unmarshal(reader, r)
}
func (r *ResponseCheckTx) MarshalJSON() ([]byte, error) {
s, err := jsonpbMarshaller.MarshalToString(r)
return []byte(s), err
@@ -126,6 +126,5 @@ var _ jsonRoundTripper = (*ResponseCommit)(nil)
var _ jsonRoundTripper = (*ResponseQuery)(nil)
var _ jsonRoundTripper = (*ResponseDeliverTx)(nil)
var _ jsonRoundTripper = (*ResponseCheckTx)(nil)
var _ jsonRoundTripper = (*ResponseSetOption)(nil)
var _ jsonRoundTripper = (*EventAttribute)(nil)

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +0,0 @@
/*
Package Behavior provides a mechanism for reactors to report behavior of peers.
Instead of a reactor calling the switch directly it will call the behavior module which will
handle the stoping and marking peer as good on behalf of the reactor.
There are four different behaviors a reactor can report.
1. bad message
type badMessage struct {
explanation string
}
This message will request the peer be stopped for an error
2. message out of order
type messageOutOfOrder struct {
explanation string
}
This message will request the peer be stopped for an error
3. consesnsus Vote
type consensusVote struct {
explanation string
}
This message will request the peer be marked as good
4. block part
type blockPart struct {
explanation string
}
This message will request the peer be marked as good
*/
package behaviour //nolint:misspell

View File

@@ -1,49 +0,0 @@
package behaviour //nolint:misspell
import (
"github.com/tendermint/tendermint/p2p"
)
// PeerBehaviour is a struct describing a behavior a peer performed.
// `peerID` identifies the peer and reason characterizes the specific
// behavior performed by the peer.
type PeerBehaviour struct {
peerID p2p.ID
reason interface{}
}
type badMessage struct {
explanation string
}
// BadMessage returns a badMessage PeerBehaviour.
func BadMessage(peerID p2p.ID, explanation string) PeerBehaviour {
return PeerBehaviour{peerID: peerID, reason: badMessage{explanation}}
}
type messageOutOfOrder struct {
explanation string
}
// MessageOutOfOrder returns a messagOutOfOrder PeerBehaviour.
func MessageOutOfOrder(peerID p2p.ID, explanation string) PeerBehaviour {
return PeerBehaviour{peerID: peerID, reason: messageOutOfOrder{explanation}}
}
type consensusVote struct {
explanation string
}
// ConsensusVote returns a consensusVote PeerBehaviour.
func ConsensusVote(peerID p2p.ID, explanation string) PeerBehaviour {
return PeerBehaviour{peerID: peerID, reason: consensusVote{explanation}}
}
type blockPart struct {
explanation string
}
// BlockPart returns blockPart PeerBehaviour.
func BlockPart(peerID p2p.ID, explanation string) PeerBehaviour {
return PeerBehaviour{peerID: peerID, reason: blockPart{explanation}}
}

View File

@@ -1,86 +0,0 @@
package behaviour //nolint:misspell
import (
"errors"
tmsync "github.com/tendermint/tendermint/libs/sync"
"github.com/tendermint/tendermint/p2p"
)
// Reporter provides an interface for reactors to report the behavior
// of peers synchronously to other components.
type Reporter interface {
Report(behavior PeerBehaviour) error
}
// SwitchReporter reports peer behavior to an internal Switch.
type SwitchReporter struct {
sw *p2p.Switch
}
// NewSwitchReporter return a new SwitchReporter instance which wraps the Switch.
func NewSwitchReporter(sw *p2p.Switch) *SwitchReporter {
return &SwitchReporter{
sw: sw,
}
}
// Report reports the behavior of a peer to the Switch.
func (spbr *SwitchReporter) Report(behavior PeerBehaviour) error {
peer := spbr.sw.Peers().Get(behavior.peerID)
if peer == nil {
return errors.New("peer not found")
}
switch reason := behavior.reason.(type) {
case consensusVote, blockPart:
spbr.sw.MarkPeerAsGood(peer)
case badMessage:
spbr.sw.StopPeerForError(peer, reason.explanation)
case messageOutOfOrder:
spbr.sw.StopPeerForError(peer, reason.explanation)
default:
return errors.New("unknown reason reported")
}
return nil
}
// MockReporter is a concrete implementation of the Reporter
// interface used in reactor tests to ensure reactors report the correct
// behavior in manufactured scenarios.
type MockReporter struct {
mtx tmsync.RWMutex
pb map[p2p.ID][]PeerBehaviour
}
// NewMockReporter returns a Reporter which records all reported
// behaviors in memory.
func NewMockReporter() *MockReporter {
return &MockReporter{
pb: map[p2p.ID][]PeerBehaviour{},
}
}
// Report stores the PeerBehaviour produced by the peer identified by peerID.
func (mpbr *MockReporter) Report(behavior PeerBehaviour) error {
mpbr.mtx.Lock()
defer mpbr.mtx.Unlock()
mpbr.pb[behavior.peerID] = append(mpbr.pb[behavior.peerID], behavior)
return nil
}
// GetBehaviours returns all behaviors reported on the peer identified by peerID.
func (mpbr *MockReporter) GetBehaviours(peerID p2p.ID) []PeerBehaviour {
mpbr.mtx.RLock()
defer mpbr.mtx.RUnlock()
if items, ok := mpbr.pb[peerID]; ok {
result := make([]PeerBehaviour, len(items))
copy(result, items)
return result
}
return []PeerBehaviour{}
}

View File

@@ -1,205 +0,0 @@
package behaviour_test //nolint:misspell
import (
"sync"
"testing"
bh "github.com/tendermint/tendermint/behaviour" //nolint:misspell
"github.com/tendermint/tendermint/p2p"
)
// TestMockReporter tests the MockReporter's ability to store reported
// peer behavior in memory indexed by the peerID.
func TestMockReporter(t *testing.T) {
var peerID p2p.ID = "MockPeer"
pr := bh.NewMockReporter()
behaviors := pr.GetBehaviours(peerID)
if len(behaviors) != 0 {
t.Error("Expected to have no behaviors reported")
}
badMessage := bh.BadMessage(peerID, "bad message")
if err := pr.Report(badMessage); err != nil {
t.Error(err)
}
behaviors = pr.GetBehaviours(peerID)
if len(behaviors) != 1 {
t.Error("Expected the peer have one reported behavior")
}
if behaviors[0] != badMessage {
t.Error("Expected Bad Message to have been reported")
}
}
type scriptItem struct {
peerID p2p.ID
behavior bh.PeerBehaviour
}
// equalBehaviours returns true if a and b contain the same PeerBehaviours with
// the same freequencies and otherwise false.
func equalBehaviours(a []bh.PeerBehaviour, b []bh.PeerBehaviour) bool {
aHistogram := map[bh.PeerBehaviour]int{}
bHistogram := map[bh.PeerBehaviour]int{}
for _, behavior := range a {
aHistogram[behavior]++
}
for _, behavior := range b {
bHistogram[behavior]++
}
if len(aHistogram) != len(bHistogram) {
return false
}
for _, behavior := range a {
if aHistogram[behavior] != bHistogram[behavior] {
return false
}
}
for _, behavior := range b {
if bHistogram[behavior] != aHistogram[behavior] {
return false
}
}
return true
}
// TestEqualPeerBehaviours tests that equalBehaviours can tell that two slices
// of peer behaviors can be compared for the behaviors they contain and the
// freequencies that those behaviors occur.
func TestEqualPeerBehaviours(t *testing.T) {
var (
peerID p2p.ID = "MockPeer"
consensusVote = bh.ConsensusVote(peerID, "voted")
blockPart = bh.BlockPart(peerID, "blocked")
equals = []struct {
left []bh.PeerBehaviour
right []bh.PeerBehaviour
}{
// Empty sets
{[]bh.PeerBehaviour{}, []bh.PeerBehaviour{}},
// Single behaviors
{[]bh.PeerBehaviour{consensusVote}, []bh.PeerBehaviour{consensusVote}},
// Equal Frequencies
{[]bh.PeerBehaviour{consensusVote, consensusVote},
[]bh.PeerBehaviour{consensusVote, consensusVote}},
// Equal frequencies different orders
{[]bh.PeerBehaviour{consensusVote, blockPart},
[]bh.PeerBehaviour{blockPart, consensusVote}},
}
unequals = []struct {
left []bh.PeerBehaviour
right []bh.PeerBehaviour
}{
// Comparing empty sets to non empty sets
{[]bh.PeerBehaviour{}, []bh.PeerBehaviour{consensusVote}},
// Different behaviors
{[]bh.PeerBehaviour{consensusVote}, []bh.PeerBehaviour{blockPart}},
// Same behavior with different frequencies
{[]bh.PeerBehaviour{consensusVote},
[]bh.PeerBehaviour{consensusVote, consensusVote}},
}
)
for _, test := range equals {
if !equalBehaviours(test.left, test.right) {
t.Errorf("expected %#v and %#v to be equal", test.left, test.right)
}
}
for _, test := range unequals {
if equalBehaviours(test.left, test.right) {
t.Errorf("expected %#v and %#v to be unequal", test.left, test.right)
}
}
}
// TestPeerBehaviourConcurrency constructs a scenario in which
// multiple goroutines are using the same MockReporter instance.
// This test reproduces the conditions in which MockReporter will
// be used within a Reactor `Receive` method tests to ensure thread safety.
func TestMockPeerBehaviourReporterConcurrency(t *testing.T) {
var (
behaviourScript = []struct {
peerID p2p.ID
behaviors []bh.PeerBehaviour
}{
{"1", []bh.PeerBehaviour{bh.ConsensusVote("1", "")}},
{"2", []bh.PeerBehaviour{bh.ConsensusVote("2", ""), bh.ConsensusVote("2", ""), bh.ConsensusVote("2", "")}},
{
"3",
[]bh.PeerBehaviour{bh.BlockPart("3", ""),
bh.ConsensusVote("3", ""),
bh.BlockPart("3", ""),
bh.ConsensusVote("3", "")}},
{
"4",
[]bh.PeerBehaviour{bh.ConsensusVote("4", ""),
bh.ConsensusVote("4", ""),
bh.ConsensusVote("4", ""),
bh.ConsensusVote("4", "")}},
{
"5",
[]bh.PeerBehaviour{bh.BlockPart("5", ""),
bh.ConsensusVote("5", ""),
bh.BlockPart("5", ""),
bh.ConsensusVote("5", "")}},
}
)
var receiveWg sync.WaitGroup
pr := bh.NewMockReporter()
scriptItems := make(chan scriptItem)
done := make(chan int)
numConsumers := 3
for i := 0; i < numConsumers; i++ {
receiveWg.Add(1)
go func() {
defer receiveWg.Done()
for {
select {
case pb := <-scriptItems:
if err := pr.Report(pb.behavior); err != nil {
t.Error(err)
}
case <-done:
return
}
}
}()
}
var sendingWg sync.WaitGroup
sendingWg.Add(1)
go func() {
defer sendingWg.Done()
for _, item := range behaviourScript {
for _, reason := range item.behaviors {
scriptItems <- scriptItem{item.peerID, reason}
}
}
}()
sendingWg.Wait()
for i := 0; i < numConsumers; i++ {
done <- 1
}
receiveWg.Wait()
for _, items := range behaviourScript {
reported := pr.GetBehaviours(items.peerID)
if !equalBehaviours(reported, items.behaviors) {
t.Errorf("expected peer %s to have behaved \nExpected: %#v \nGot %#v \n",
items.peerID, items.behaviors, reported)
}
}
}

View File

@@ -1,211 +0,0 @@
package v1
import (
"fmt"
"math"
"time"
flow "github.com/tendermint/tendermint/libs/flowrate"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
//--------
// Peer
// BpPeerParams stores the peer parameters that are used when creating a peer.
type BpPeerParams struct {
timeout time.Duration
minRecvRate int64
sampleRate time.Duration
windowSize time.Duration
}
// BpPeer is the datastructure associated with a fast sync peer.
type BpPeer struct {
logger log.Logger
ID p2p.ID
Base int64 // the peer reported base
Height int64 // the peer reported height
NumPendingBlockRequests int // number of requests still waiting for block responses
blocks map[int64]*types.Block // blocks received or expected to be received from this peer
blockResponseTimer *time.Timer
recvMonitor *flow.Monitor
params *BpPeerParams // parameters for timer and monitor
onErr func(err error, peerID p2p.ID) // function to call on error
}
// NewBpPeer creates a new peer.
func NewBpPeer(peerID p2p.ID, base int64, height int64,
onErr func(err error, peerID p2p.ID), params *BpPeerParams) *BpPeer {
if params == nil {
params = BpPeerDefaultParams()
}
return &BpPeer{
ID: peerID,
Base: base,
Height: height,
blocks: make(map[int64]*types.Block, maxRequestsPerPeer),
logger: log.NewNopLogger(),
onErr: onErr,
params: params,
}
}
// String returns a string representation of a peer.
func (peer *BpPeer) String() string {
return fmt.Sprintf("peer: %v height: %v pending: %v", peer.ID, peer.Height, peer.NumPendingBlockRequests)
}
// SetLogger sets the logger of the peer.
func (peer *BpPeer) SetLogger(l log.Logger) {
peer.logger = l
}
// Cleanup performs cleanup of the peer, removes blocks, requests, stops timer and monitor.
func (peer *BpPeer) Cleanup() {
if peer.blockResponseTimer != nil {
peer.blockResponseTimer.Stop()
}
if peer.NumPendingBlockRequests != 0 {
peer.logger.Info("peer with pending requests is being cleaned", "peer", peer.ID)
}
if len(peer.blocks)-peer.NumPendingBlockRequests != 0 {
peer.logger.Info("peer with pending blocks is being cleaned", "peer", peer.ID)
}
for h := range peer.blocks {
delete(peer.blocks, h)
}
peer.NumPendingBlockRequests = 0
peer.recvMonitor = nil
}
// BlockAtHeight returns the block at a given height if available and errMissingBlock otherwise.
func (peer *BpPeer) BlockAtHeight(height int64) (*types.Block, error) {
block, ok := peer.blocks[height]
if !ok {
return nil, errMissingBlock
}
if block == nil {
return nil, errMissingBlock
}
return peer.blocks[height], nil
}
// AddBlock adds a block at peer level. Block must be non-nil and recvSize a positive integer
// The peer must have a pending request for this block.
func (peer *BpPeer) AddBlock(block *types.Block, recvSize int) error {
if block == nil || recvSize < 0 {
panic("bad parameters")
}
existingBlock, ok := peer.blocks[block.Height]
if !ok {
peer.logger.Error("unsolicited block", "blockHeight", block.Height, "peer", peer.ID)
return errMissingBlock
}
if existingBlock != nil {
peer.logger.Error("already have a block for height", "height", block.Height)
return errDuplicateBlock
}
if peer.NumPendingBlockRequests == 0 {
panic("peer does not have pending requests")
}
peer.blocks[block.Height] = block
peer.NumPendingBlockRequests--
if peer.NumPendingBlockRequests == 0 {
peer.stopMonitor()
peer.stopBlockResponseTimer()
} else {
peer.recvMonitor.Update(recvSize)
peer.resetBlockResponseTimer()
}
return nil
}
// RemoveBlock removes the block of given height
func (peer *BpPeer) RemoveBlock(height int64) {
delete(peer.blocks, height)
}
// RequestSent records that a request was sent, and starts the peer timer and monitor if needed.
func (peer *BpPeer) RequestSent(height int64) {
peer.blocks[height] = nil
if peer.NumPendingBlockRequests == 0 {
peer.startMonitor()
peer.resetBlockResponseTimer()
}
peer.NumPendingBlockRequests++
}
// CheckRate verifies that the response rate of the peer is acceptable (higher than the minimum allowed).
func (peer *BpPeer) CheckRate() error {
if peer.NumPendingBlockRequests == 0 {
return nil
}
curRate := peer.recvMonitor.Status().CurRate
// curRate can be 0 on start
if curRate != 0 && curRate < peer.params.minRecvRate {
err := errSlowPeer
peer.logger.Error("SendTimeout", "peer", peer,
"reason", err,
"curRate", fmt.Sprintf("%d KB/s", curRate/1024),
"minRate", fmt.Sprintf("%d KB/s", peer.params.minRecvRate/1024))
return err
}
return nil
}
func (peer *BpPeer) onTimeout() {
peer.onErr(errNoPeerResponse, peer.ID)
}
func (peer *BpPeer) stopMonitor() {
peer.recvMonitor.Done()
peer.recvMonitor = nil
}
func (peer *BpPeer) startMonitor() {
peer.recvMonitor = flow.New(peer.params.sampleRate, peer.params.windowSize)
initialValue := float64(peer.params.minRecvRate) * math.E
peer.recvMonitor.SetREMA(initialValue)
}
func (peer *BpPeer) resetBlockResponseTimer() {
if peer.blockResponseTimer == nil {
peer.blockResponseTimer = time.AfterFunc(peer.params.timeout, peer.onTimeout)
} else {
peer.blockResponseTimer.Reset(peer.params.timeout)
}
}
func (peer *BpPeer) stopBlockResponseTimer() bool {
if peer.blockResponseTimer == nil {
return false
}
return peer.blockResponseTimer.Stop()
}
// BpPeerDefaultParams returns the default peer parameters.
func BpPeerDefaultParams() *BpPeerParams {
return &BpPeerParams{
// Timeout for a peer to respond to a block request.
timeout: 15 * time.Second,
// Minimum recv rate to ensure we're receiving blocks from a peer fast
// enough. If a peer is not sending data at at least that rate, we
// consider them to have timedout and we disconnect.
//
// Assuming a DSL connection (not a good choice) 128 Kbps (upload) ~ 15 KB/s,
// sending data across atlantic ~ 7.5 KB/s.
minRecvRate: int64(7680),
// Monitor parameters
sampleRate: time.Second,
windowSize: 40 * time.Second,
}
}

View File

@@ -1,280 +0,0 @@
package v1
import (
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/log"
tmrand "github.com/tendermint/tendermint/libs/rand"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
func TestPeerMonitor(t *testing.T) {
peer := NewBpPeer(
p2p.ID(tmrand.Str(12)), 0, 10,
func(err error, _ p2p.ID) {},
nil)
peer.SetLogger(log.TestingLogger())
peer.startMonitor()
assert.NotNil(t, peer.recvMonitor)
peer.stopMonitor()
assert.Nil(t, peer.recvMonitor)
}
func TestPeerResetBlockResponseTimer(t *testing.T) {
var (
numErrFuncCalls int // number of calls to the errFunc
lastErr error // last generated error
peerTestMtx sync.Mutex // modifications of ^^ variables are also done from timer handler goroutine
)
params := &BpPeerParams{timeout: 20 * time.Millisecond}
peer := NewBpPeer(
p2p.ID(tmrand.Str(12)), 0, 10,
func(err error, _ p2p.ID) {
peerTestMtx.Lock()
defer peerTestMtx.Unlock()
lastErr = err
numErrFuncCalls++
},
params)
peer.SetLogger(log.TestingLogger())
checkByStoppingPeerTimer(t, peer, false)
// initial reset call with peer having a nil timer
peer.resetBlockResponseTimer()
assert.NotNil(t, peer.blockResponseTimer)
// make sure timer is running and stop it
checkByStoppingPeerTimer(t, peer, true)
// reset with running timer
peer.resetBlockResponseTimer()
time.Sleep(5 * time.Millisecond)
peer.resetBlockResponseTimer()
assert.NotNil(t, peer.blockResponseTimer)
// let the timer expire and ...
time.Sleep(50 * time.Millisecond)
// ... check timer is not running
checkByStoppingPeerTimer(t, peer, false)
peerTestMtx.Lock()
// ... check errNoPeerResponse has been sent
assert.Equal(t, 1, numErrFuncCalls)
assert.Equal(t, lastErr, errNoPeerResponse)
peerTestMtx.Unlock()
}
func TestPeerRequestSent(t *testing.T) {
params := &BpPeerParams{timeout: 2 * time.Millisecond}
peer := NewBpPeer(
p2p.ID(tmrand.Str(12)), 0, 10,
func(err error, _ p2p.ID) {},
params)
peer.SetLogger(log.TestingLogger())
peer.RequestSent(1)
assert.NotNil(t, peer.recvMonitor)
assert.NotNil(t, peer.blockResponseTimer)
assert.Equal(t, 1, peer.NumPendingBlockRequests)
peer.RequestSent(1)
assert.NotNil(t, peer.recvMonitor)
assert.NotNil(t, peer.blockResponseTimer)
assert.Equal(t, 2, peer.NumPendingBlockRequests)
}
func TestPeerGetAndRemoveBlock(t *testing.T) {
peer := NewBpPeer(
p2p.ID(tmrand.Str(12)), 0, 100,
func(err error, _ p2p.ID) {},
nil)
// Change peer height
peer.Height = int64(10)
assert.Equal(t, int64(10), peer.Height)
// request some blocks and receive few of them
for i := 1; i <= 10; i++ {
peer.RequestSent(int64(i))
if i > 5 {
// only receive blocks 1..5
continue
}
_ = peer.AddBlock(makeSmallBlock(i), 10)
}
tests := []struct {
name string
height int64
wantErr error
blockPresent bool
}{
{"no request", 100, errMissingBlock, false},
{"no block", 6, errMissingBlock, false},
{"block 1 present", 1, nil, true},
{"block max present", 5, nil, true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
// try to get the block
b, err := peer.BlockAtHeight(tt.height)
assert.Equal(t, tt.wantErr, err)
assert.Equal(t, tt.blockPresent, b != nil)
// remove the block
peer.RemoveBlock(tt.height)
_, err = peer.BlockAtHeight(tt.height)
assert.Equal(t, errMissingBlock, err)
})
}
}
func TestPeerAddBlock(t *testing.T) {
peer := NewBpPeer(
p2p.ID(tmrand.Str(12)), 0, 100,
func(err error, _ p2p.ID) {},
nil)
// request some blocks, receive one
for i := 1; i <= 10; i++ {
peer.RequestSent(int64(i))
if i == 5 {
// receive block 5
_ = peer.AddBlock(makeSmallBlock(i), 10)
}
}
tests := []struct {
name string
height int64
wantErr error
blockPresent bool
}{
{"no request", 50, errMissingBlock, false},
{"duplicate block", 5, errDuplicateBlock, true},
{"block 1 successfully received", 1, nil, true},
{"block max successfully received", 10, nil, true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
// try to get the block
err := peer.AddBlock(makeSmallBlock(int(tt.height)), 10)
assert.Equal(t, tt.wantErr, err)
_, err = peer.BlockAtHeight(tt.height)
assert.Equal(t, tt.blockPresent, err == nil)
})
}
}
func TestPeerOnErrFuncCalledDueToExpiration(t *testing.T) {
params := &BpPeerParams{timeout: 10 * time.Millisecond}
var (
numErrFuncCalls int // number of calls to the onErr function
lastErr error // last generated error
peerTestMtx sync.Mutex // modifications of ^^ variables are also done from timer handler goroutine
)
peer := NewBpPeer(
p2p.ID(tmrand.Str(12)), 0, 10,
func(err error, _ p2p.ID) {
peerTestMtx.Lock()
defer peerTestMtx.Unlock()
lastErr = err
numErrFuncCalls++
},
params)
peer.SetLogger(log.TestingLogger())
peer.RequestSent(1)
time.Sleep(50 * time.Millisecond)
// timer should have expired by now, check that the on error function was called
peerTestMtx.Lock()
assert.Equal(t, 1, numErrFuncCalls)
assert.Equal(t, errNoPeerResponse, lastErr)
peerTestMtx.Unlock()
}
func TestPeerCheckRate(t *testing.T) {
params := &BpPeerParams{
timeout: time.Second,
minRecvRate: int64(100), // 100 bytes/sec exponential moving average
}
peer := NewBpPeer(
p2p.ID(tmrand.Str(12)), 0, 10,
func(err error, _ p2p.ID) {},
params)
peer.SetLogger(log.TestingLogger())
require.Nil(t, peer.CheckRate())
for i := 0; i < 40; i++ {
peer.RequestSent(int64(i))
}
// monitor starts with a higher rEMA (~ 2*minRecvRate), wait for it to go down
time.Sleep(900 * time.Millisecond)
// normal peer - send a bit more than 100 bytes/sec, > 10 bytes/100msec, check peer is not considered slow
for i := 0; i < 10; i++ {
_ = peer.AddBlock(makeSmallBlock(i), 11)
time.Sleep(100 * time.Millisecond)
require.Nil(t, peer.CheckRate())
}
// slow peer - send a bit less than 10 bytes/100msec
for i := 10; i < 20; i++ {
_ = peer.AddBlock(makeSmallBlock(i), 9)
time.Sleep(100 * time.Millisecond)
}
// check peer is considered slow
assert.Equal(t, errSlowPeer, peer.CheckRate())
}
func TestPeerCleanup(t *testing.T) {
params := &BpPeerParams{timeout: 2 * time.Millisecond}
peer := NewBpPeer(
p2p.ID(tmrand.Str(12)), 0, 10,
func(err error, _ p2p.ID) {},
params)
peer.SetLogger(log.TestingLogger())
assert.Nil(t, peer.blockResponseTimer)
peer.RequestSent(1)
assert.NotNil(t, peer.blockResponseTimer)
peer.Cleanup()
checkByStoppingPeerTimer(t, peer, false)
}
// Check if peer timer is running or not (a running timer can be successfully stopped).
// Note: stops the timer.
func checkByStoppingPeerTimer(t *testing.T, peer *BpPeer, running bool) {
assert.NotPanics(t, func() {
stopped := peer.stopBlockResponseTimer()
if running {
assert.True(t, stopped)
} else {
assert.False(t, stopped)
}
})
}
func makeSmallBlock(height int) *types.Block {
return types.MakeBlock(int64(height), []types.Tx{types.Tx("foo")}, nil, nil)
}

View File

@@ -1,370 +0,0 @@
package v1
import (
"sort"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
// BlockPool keeps track of the fast sync peers, block requests and block responses.
type BlockPool struct {
logger log.Logger
// Set of peers that have sent status responses, with height bigger than pool.Height
peers map[p2p.ID]*BpPeer
// Set of block heights and the corresponding peers from where a block response is expected or has been received.
blocks map[int64]p2p.ID
plannedRequests map[int64]struct{} // list of blocks to be assigned peers for blockRequest
nextRequestHeight int64 // next height to be added to plannedRequests
Height int64 // height of next block to execute
MaxPeerHeight int64 // maximum height of all peers
toBcR bcReactor
}
// NewBlockPool creates a new BlockPool.
func NewBlockPool(height int64, toBcR bcReactor) *BlockPool {
return &BlockPool{
Height: height,
MaxPeerHeight: 0,
peers: make(map[p2p.ID]*BpPeer),
blocks: make(map[int64]p2p.ID),
plannedRequests: make(map[int64]struct{}),
nextRequestHeight: height,
toBcR: toBcR,
}
}
// SetLogger sets the logger of the pool.
func (pool *BlockPool) SetLogger(l log.Logger) {
pool.logger = l
}
// ReachedMaxHeight check if the pool has reached the maximum peer height.
func (pool *BlockPool) ReachedMaxHeight() bool {
return pool.Height >= pool.MaxPeerHeight
}
func (pool *BlockPool) rescheduleRequest(peerID p2p.ID, height int64) {
pool.logger.Info("reschedule requests made to peer for height ", "peerID", peerID, "height", height)
pool.plannedRequests[height] = struct{}{}
delete(pool.blocks, height)
pool.peers[peerID].RemoveBlock(height)
}
// Updates the pool's max height. If no peers are left MaxPeerHeight is set to 0.
func (pool *BlockPool) updateMaxPeerHeight() {
var newMax int64
for _, peer := range pool.peers {
peerHeight := peer.Height
if peerHeight > newMax {
newMax = peerHeight
}
}
pool.MaxPeerHeight = newMax
}
// UpdatePeer adds a new peer or updates an existing peer with a new base and height.
// If a peer is short it is not added.
func (pool *BlockPool) UpdatePeer(peerID p2p.ID, base int64, height int64) error {
peer := pool.peers[peerID]
if peer == nil {
if height < pool.Height {
pool.logger.Info("Peer height too small",
"peer", peerID, "height", height, "fsm_height", pool.Height)
return errPeerTooShort
}
// Add new peer.
peer = NewBpPeer(peerID, base, height, pool.toBcR.sendPeerError, nil)
peer.SetLogger(pool.logger.With("peer", peerID))
pool.peers[peerID] = peer
pool.logger.Info("added peer", "peerID", peerID, "base", base, "height", height, "num_peers", len(pool.peers))
} else {
// Check if peer is lowering its height. This is not allowed.
if height < peer.Height {
pool.RemovePeer(peerID, errPeerLowersItsHeight)
return errPeerLowersItsHeight
}
// Update existing peer.
peer.Base = base
peer.Height = height
}
// Update the pool's MaxPeerHeight if needed.
pool.updateMaxPeerHeight()
return nil
}
// Cleans and deletes the peer. Recomputes the max peer height.
func (pool *BlockPool) deletePeer(peer *BpPeer) {
if peer == nil {
return
}
peer.Cleanup()
delete(pool.peers, peer.ID)
if peer.Height == pool.MaxPeerHeight {
pool.updateMaxPeerHeight()
}
}
// RemovePeer removes the blocks and requests from the peer, reschedules them and deletes the peer.
func (pool *BlockPool) RemovePeer(peerID p2p.ID, err error) {
peer := pool.peers[peerID]
if peer == nil {
return
}
pool.logger.Info("removing peer", "peerID", peerID, "error", err)
// Reschedule the block requests made to the peer, or received and not processed yet.
// Note that some of the requests may be removed further down.
for h := range pool.peers[peerID].blocks {
pool.rescheduleRequest(peerID, h)
}
oldMaxPeerHeight := pool.MaxPeerHeight
// Delete the peer. This operation may result in the pool's MaxPeerHeight being lowered.
pool.deletePeer(peer)
// Check if the pool's MaxPeerHeight has been lowered.
// This may happen if the tallest peer has been removed.
if oldMaxPeerHeight > pool.MaxPeerHeight {
// Remove any planned requests for heights over the new MaxPeerHeight.
for h := range pool.plannedRequests {
if h > pool.MaxPeerHeight {
delete(pool.plannedRequests, h)
}
}
// Adjust the nextRequestHeight to the new max plus one.
if pool.nextRequestHeight > pool.MaxPeerHeight {
pool.nextRequestHeight = pool.MaxPeerHeight + 1
}
}
}
func (pool *BlockPool) removeShortPeers() {
for _, peer := range pool.peers {
if peer.Height < pool.Height {
pool.RemovePeer(peer.ID, nil)
}
}
}
func (pool *BlockPool) removeBadPeers() {
pool.removeShortPeers()
for _, peer := range pool.peers {
if err := peer.CheckRate(); err != nil {
pool.RemovePeer(peer.ID, err)
pool.toBcR.sendPeerError(err, peer.ID)
}
}
}
// MakeNextRequests creates more requests if the block pool is running low.
func (pool *BlockPool) MakeNextRequests(maxNumRequests int) {
heights := pool.makeRequestBatch(maxNumRequests)
if len(heights) != 0 {
pool.logger.Info("makeNextRequests will make following requests",
"number", len(heights), "heights", heights)
}
for _, height := range heights {
h := int64(height)
if !pool.sendRequest(h) {
// If a good peer was not found for sending the request at height h then return,
// as it shouldn't be possible to find a peer for h+1.
return
}
delete(pool.plannedRequests, h)
}
}
// Makes a batch of requests sorted by height such that the block pool has up to maxNumRequests entries.
func (pool *BlockPool) makeRequestBatch(maxNumRequests int) []int {
pool.removeBadPeers()
// At this point pool.requests may include heights for requests to be redone due to removal of peers:
// - peers timed out or were removed by switch
// - FSM timed out on waiting to advance the block execution due to missing blocks at h or h+1
// Determine the number of requests needed by subtracting the number of requests already made from the maximum
// allowed
numNeeded := maxNumRequests - len(pool.blocks)
for len(pool.plannedRequests) < numNeeded {
if pool.nextRequestHeight > pool.MaxPeerHeight {
break
}
pool.plannedRequests[pool.nextRequestHeight] = struct{}{}
pool.nextRequestHeight++
}
heights := make([]int, 0, len(pool.plannedRequests))
for k := range pool.plannedRequests {
heights = append(heights, int(k))
}
sort.Ints(heights)
return heights
}
func (pool *BlockPool) sendRequest(height int64) bool {
for _, peer := range pool.peers {
if peer.NumPendingBlockRequests >= maxRequestsPerPeer {
continue
}
if peer.Base > height || peer.Height < height {
continue
}
err := pool.toBcR.sendBlockRequest(peer.ID, height)
if err == errNilPeerForBlockRequest {
// Switch does not have this peer, remove it and continue to look for another peer.
pool.logger.Error("switch does not have peer..removing peer selected for height", "peer",
peer.ID, "height", height)
pool.RemovePeer(peer.ID, err)
continue
}
if err == errSendQueueFull {
pool.logger.Error("peer queue is full", "peer", peer.ID, "height", height)
continue
}
pool.logger.Info("assigned request to peer", "peer", peer.ID, "height", height)
pool.blocks[height] = peer.ID
peer.RequestSent(height)
return true
}
pool.logger.Error("could not find peer to send request for block at height", "height", height)
return false
}
// AddBlock validates that the block comes from the peer it was expected from and stores it in the 'blocks' map.
func (pool *BlockPool) AddBlock(peerID p2p.ID, block *types.Block, blockSize int) error {
peer, ok := pool.peers[peerID]
if !ok {
pool.logger.Error("block from unknown peer", "height", block.Height, "peer", peerID)
return errBadDataFromPeer
}
if wantPeerID, ok := pool.blocks[block.Height]; ok && wantPeerID != peerID {
pool.logger.Error("block received from wrong peer", "height", block.Height,
"peer", peerID, "expected_peer", wantPeerID)
return errBadDataFromPeer
}
return peer.AddBlock(block, blockSize)
}
// BlockData stores the peer responsible to deliver a block and the actual block if delivered.
type BlockData struct {
block *types.Block
peer *BpPeer
}
// BlockAndPeerAtHeight retrieves the block and delivery peer at specified height.
// Returns errMissingBlock if a block was not found
func (pool *BlockPool) BlockAndPeerAtHeight(height int64) (bData *BlockData, err error) {
peerID := pool.blocks[height]
peer := pool.peers[peerID]
if peer == nil {
return nil, errMissingBlock
}
block, err := peer.BlockAtHeight(height)
if err != nil {
return nil, err
}
return &BlockData{peer: peer, block: block}, nil
}
// FirstTwoBlocksAndPeers returns the blocks and the delivery peers at pool's height H and H+1.
func (pool *BlockPool) FirstTwoBlocksAndPeers() (first, second *BlockData, err error) {
first, err = pool.BlockAndPeerAtHeight(pool.Height)
second, err2 := pool.BlockAndPeerAtHeight(pool.Height + 1)
if err == nil {
err = err2
}
return
}
// InvalidateFirstTwoBlocks removes the peers that sent us the first two blocks, blocks are removed by RemovePeer().
func (pool *BlockPool) InvalidateFirstTwoBlocks(err error) {
first, err1 := pool.BlockAndPeerAtHeight(pool.Height)
second, err2 := pool.BlockAndPeerAtHeight(pool.Height + 1)
if err1 == nil {
pool.RemovePeer(first.peer.ID, err)
}
if err2 == nil {
pool.RemovePeer(second.peer.ID, err)
}
}
// ProcessedCurrentHeightBlock performs cleanup after a block is processed. It removes block at pool height and
// the peers that are now short.
func (pool *BlockPool) ProcessedCurrentHeightBlock() {
peerID, peerOk := pool.blocks[pool.Height]
if peerOk {
pool.peers[peerID].RemoveBlock(pool.Height)
}
delete(pool.blocks, pool.Height)
pool.logger.Debug("removed block at height", "height", pool.Height)
pool.Height++
pool.removeShortPeers()
}
// RemovePeerAtCurrentHeights checks if a block at pool's height H exists and if not, it removes the
// delivery peer and returns. If a block at height H exists then the check and peer removal is done for H+1.
// This function is called when the FSM is not able to make progress for some time.
// This happens if either the block H or H+1 have not been delivered.
func (pool *BlockPool) RemovePeerAtCurrentHeights(err error) {
peerID := pool.blocks[pool.Height]
peer, ok := pool.peers[peerID]
if ok {
if _, err := peer.BlockAtHeight(pool.Height); err != nil {
pool.logger.Info("remove peer that hasn't sent block at pool.Height",
"peer", peerID, "height", pool.Height)
pool.RemovePeer(peerID, err)
return
}
}
peerID = pool.blocks[pool.Height+1]
peer, ok = pool.peers[peerID]
if ok {
if _, err := peer.BlockAtHeight(pool.Height + 1); err != nil {
pool.logger.Info("remove peer that hasn't sent block at pool.Height+1",
"peer", peerID, "height", pool.Height+1)
pool.RemovePeer(peerID, err)
return
}
}
}
// Cleanup performs pool and peer cleanup
func (pool *BlockPool) Cleanup() {
for id, peer := range pool.peers {
peer.Cleanup()
delete(pool.peers, id)
}
pool.plannedRequests = make(map[int64]struct{})
pool.blocks = make(map[int64]p2p.ID)
pool.nextRequestHeight = 0
pool.Height = 0
pool.MaxPeerHeight = 0
}
// NumPeers returns the number of peers in the pool
func (pool *BlockPool) NumPeers() int {
return len(pool.peers)
}
// NeedsBlocks returns true if more blocks are required.
func (pool *BlockPool) NeedsBlocks() bool {
return len(pool.blocks) < maxNumRequests
}

View File

@@ -1,691 +0,0 @@
package v1
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
type testPeer struct {
id p2p.ID
base int64
height int64
}
type testBcR struct {
logger log.Logger
}
type testValues struct {
numRequestsSent int
}
var testResults testValues
func resetPoolTestResults() {
testResults.numRequestsSent = 0
}
func (testR *testBcR) sendPeerError(err error, peerID p2p.ID) {
}
func (testR *testBcR) sendStatusRequest() {
}
func (testR *testBcR) sendBlockRequest(peerID p2p.ID, height int64) error {
testResults.numRequestsSent++
return nil
}
func (testR *testBcR) resetStateTimer(name string, timer **time.Timer, timeout time.Duration) {
}
func (testR *testBcR) switchToConsensus() {
}
func newTestBcR() *testBcR {
testBcR := &testBcR{logger: log.TestingLogger()}
return testBcR
}
type tPBlocks struct {
id p2p.ID
create bool
}
// Makes a block pool with specified current height, list of peers, block requests and block responses
func makeBlockPool(bcr *testBcR, height int64, peers []BpPeer, blocks map[int64]tPBlocks) *BlockPool {
bPool := NewBlockPool(height, bcr)
bPool.SetLogger(bcr.logger)
txs := []types.Tx{types.Tx("foo"), types.Tx("bar")}
var maxH int64
for _, p := range peers {
if p.Height > maxH {
maxH = p.Height
}
bPool.peers[p.ID] = NewBpPeer(p.ID, p.Base, p.Height, bcr.sendPeerError, nil)
bPool.peers[p.ID].SetLogger(bcr.logger)
}
bPool.MaxPeerHeight = maxH
for h, p := range blocks {
bPool.blocks[h] = p.id
bPool.peers[p.id].RequestSent(h)
if p.create {
// simulate that a block at height h has been received
_ = bPool.peers[p.id].AddBlock(types.MakeBlock(h, txs, nil, nil), 100)
}
}
return bPool
}
func assertPeerSetsEquivalent(t *testing.T, set1 map[p2p.ID]*BpPeer, set2 map[p2p.ID]*BpPeer) {
assert.Equal(t, len(set1), len(set2))
for peerID, peer1 := range set1 {
peer2 := set2[peerID]
assert.NotNil(t, peer2)
assert.Equal(t, peer1.NumPendingBlockRequests, peer2.NumPendingBlockRequests)
assert.Equal(t, peer1.Height, peer2.Height)
assert.Equal(t, peer1.Base, peer2.Base)
assert.Equal(t, len(peer1.blocks), len(peer2.blocks))
for h, block1 := range peer1.blocks {
block2 := peer2.blocks[h]
// block1 and block2 could be nil if a request was made but no block was received
assert.Equal(t, block1, block2)
}
}
}
func assertBlockPoolEquivalent(t *testing.T, poolWanted, pool *BlockPool) {
assert.Equal(t, poolWanted.blocks, pool.blocks)
assertPeerSetsEquivalent(t, poolWanted.peers, pool.peers)
assert.Equal(t, poolWanted.MaxPeerHeight, pool.MaxPeerHeight)
assert.Equal(t, poolWanted.Height, pool.Height)
}
func TestBlockPoolUpdatePeer(t *testing.T) {
testBcR := newTestBcR()
tests := []struct {
name string
pool *BlockPool
args testPeer
poolWanted *BlockPool
errWanted error
}{
{
name: "add a first short peer",
pool: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
args: testPeer{"P1", 0, 50},
errWanted: errPeerTooShort,
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
},
{
name: "add a first good peer",
pool: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
args: testPeer{"P1", 0, 101},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 101}}, map[int64]tPBlocks{}),
},
{
name: "add a first good peer with base",
pool: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
args: testPeer{"P1", 10, 101},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Base: 10, Height: 101}}, map[int64]tPBlocks{}),
},
{
name: "increase the height of P1 from 120 to 123",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
args: testPeer{"P1", 0, 123},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 123}}, map[int64]tPBlocks{}),
},
{
name: "decrease the height of P1 from 120 to 110",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
args: testPeer{"P1", 0, 110},
errWanted: errPeerLowersItsHeight,
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
},
{
name: "decrease the height of P1 from 105 to 102 with blocks",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 105}},
map[int64]tPBlocks{
100: {"P1", true}, 101: {"P1", true}, 102: {"P1", true}}),
args: testPeer{"P1", 0, 102},
errWanted: errPeerLowersItsHeight,
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{},
map[int64]tPBlocks{}),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
pool := tt.pool
err := pool.UpdatePeer(tt.args.id, tt.args.base, tt.args.height)
assert.Equal(t, tt.errWanted, err)
assert.Equal(t, tt.poolWanted.blocks, tt.pool.blocks)
assertPeerSetsEquivalent(t, tt.poolWanted.peers, tt.pool.peers)
assert.Equal(t, tt.poolWanted.MaxPeerHeight, tt.pool.MaxPeerHeight)
})
}
}
func TestBlockPoolRemovePeer(t *testing.T) {
testBcR := newTestBcR()
type args struct {
peerID p2p.ID
err error
}
tests := []struct {
name string
pool *BlockPool
args args
poolWanted *BlockPool
}{
{
name: "attempt to delete non-existing peer",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
args: args{"P99", nil},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
},
{
name: "delete the only peer without blocks",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
args: args{"P1", nil},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
},
{
name: "delete the shortest of two peers without blocks",
pool: makeBlockPool(
testBcR,
100,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 120}},
map[int64]tPBlocks{}),
args: args{"P1", nil},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P2", Height: 120}}, map[int64]tPBlocks{}),
},
{
name: "delete the tallest of two peers without blocks",
pool: makeBlockPool(
testBcR,
100,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 120}},
map[int64]tPBlocks{}),
args: args{"P2", nil},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 100}}, map[int64]tPBlocks{}),
},
{
name: "delete the only peer with block requests sent and blocks received",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}},
map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", false}}),
args: args{"P1", nil},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
},
{
name: "delete the shortest of two peers with block requests sent and blocks received",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 200}},
map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", false}}),
args: args{"P1", nil},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P2", Height: 200}}, map[int64]tPBlocks{}),
},
{
name: "delete the tallest of two peers with block requests sent and blocks received",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 110}},
map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", false}}),
args: args{"P1", nil},
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P2", Height: 110}}, map[int64]tPBlocks{}),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
tt.pool.RemovePeer(tt.args.peerID, tt.args.err)
assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
})
}
}
func TestBlockPoolRemoveShortPeers(t *testing.T) {
testBcR := newTestBcR()
tests := []struct {
name string
pool *BlockPool
poolWanted *BlockPool
}{
{
name: "no short peers",
pool: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 110}, {ID: "P3", Height: 120}}, map[int64]tPBlocks{}),
poolWanted: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 110}, {ID: "P3", Height: 120}}, map[int64]tPBlocks{}),
},
{
name: "one short peer",
pool: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 90}, {ID: "P3", Height: 120}}, map[int64]tPBlocks{}),
poolWanted: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P3", Height: 120}}, map[int64]tPBlocks{}),
},
{
name: "all short peers",
pool: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P1", Height: 90}, {ID: "P2", Height: 91}, {ID: "P3", Height: 92}}, map[int64]tPBlocks{}),
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
pool := tt.pool
pool.removeShortPeers()
assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
})
}
}
func TestBlockPoolSendRequestBatch(t *testing.T) {
type testPeerResult struct {
id p2p.ID
numPendingBlockRequests int
}
testBcR := newTestBcR()
tests := []struct {
name string
pool *BlockPool
maxRequestsPerPeer int
expRequests map[int64]bool
expRequestsSent int
expPeerResults []testPeerResult
}{
{
name: "one peer - send up to maxRequestsPerPeer block requests",
pool: makeBlockPool(testBcR, 10, []BpPeer{{ID: "P1", Height: 100}}, map[int64]tPBlocks{}),
maxRequestsPerPeer: 2,
expRequests: map[int64]bool{10: true, 11: true},
expRequestsSent: 2,
expPeerResults: []testPeerResult{{id: "P1", numPendingBlockRequests: 2}},
},
{
name: "multiple peers - stops at gap between height and base",
pool: makeBlockPool(testBcR, 10, []BpPeer{
{ID: "P1", Base: 1, Height: 12},
{ID: "P2", Base: 15, Height: 100},
}, map[int64]tPBlocks{}),
maxRequestsPerPeer: 10,
expRequests: map[int64]bool{10: true, 11: true, 12: true},
expRequestsSent: 3,
expPeerResults: []testPeerResult{
{id: "P1", numPendingBlockRequests: 3},
{id: "P2", numPendingBlockRequests: 0},
},
},
{
name: "n peers - send n*maxRequestsPerPeer block requests",
pool: makeBlockPool(
testBcR,
10,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{}),
maxRequestsPerPeer: 2,
expRequests: map[int64]bool{10: true, 11: true},
expRequestsSent: 4,
expPeerResults: []testPeerResult{
{id: "P1", numPendingBlockRequests: 2},
{id: "P2", numPendingBlockRequests: 2}},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
resetPoolTestResults()
var pool = tt.pool
maxRequestsPerPeer = tt.maxRequestsPerPeer
pool.MakeNextRequests(10)
assert.Equal(t, tt.expRequestsSent, testResults.numRequestsSent)
for _, tPeer := range tt.expPeerResults {
var peer = pool.peers[tPeer.id]
assert.NotNil(t, peer)
assert.Equal(t, tPeer.numPendingBlockRequests, peer.NumPendingBlockRequests)
}
})
}
}
func TestBlockPoolAddBlock(t *testing.T) {
testBcR := newTestBcR()
txs := []types.Tx{types.Tx("foo"), types.Tx("bar")}
type args struct {
peerID p2p.ID
block *types.Block
blockSize int
}
tests := []struct {
name string
pool *BlockPool
args args
poolWanted *BlockPool
errWanted error
}{
{name: "block from unknown peer",
pool: makeBlockPool(testBcR, 10, []BpPeer{{ID: "P1", Height: 100}}, map[int64]tPBlocks{}),
args: args{
peerID: "P2",
block: types.MakeBlock(int64(10), txs, nil, nil),
blockSize: 100,
},
poolWanted: makeBlockPool(testBcR, 10, []BpPeer{{ID: "P1", Height: 100}}, map[int64]tPBlocks{}),
errWanted: errBadDataFromPeer,
},
{name: "unexpected block 11 from known peer - waiting for 10",
pool: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}},
map[int64]tPBlocks{10: {"P1", false}}),
args: args{
peerID: "P1",
block: types.MakeBlock(int64(11), txs, nil, nil),
blockSize: 100,
},
poolWanted: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}},
map[int64]tPBlocks{10: {"P1", false}}),
errWanted: errMissingBlock,
},
{name: "unexpected block 10 from known peer - already have 10",
pool: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}},
map[int64]tPBlocks{10: {"P1", true}, 11: {"P1", false}}),
args: args{
peerID: "P1",
block: types.MakeBlock(int64(10), txs, nil, nil),
blockSize: 100,
},
poolWanted: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}},
map[int64]tPBlocks{10: {"P1", true}, 11: {"P1", false}}),
errWanted: errDuplicateBlock,
},
{name: "unexpected block 10 from known peer P2 - expected 10 to come from P1",
pool: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{10: {"P1", false}}),
args: args{
peerID: "P2",
block: types.MakeBlock(int64(10), txs, nil, nil),
blockSize: 100,
},
poolWanted: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{10: {"P1", false}}),
errWanted: errBadDataFromPeer,
},
{name: "expected block from known peer",
pool: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}},
map[int64]tPBlocks{10: {"P1", false}}),
args: args{
peerID: "P1",
block: types.MakeBlock(int64(10), txs, nil, nil),
blockSize: 100,
},
poolWanted: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}},
map[int64]tPBlocks{10: {"P1", true}}),
errWanted: nil,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
err := tt.pool.AddBlock(tt.args.peerID, tt.args.block, tt.args.blockSize)
assert.Equal(t, tt.errWanted, err)
assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
})
}
}
func TestBlockPoolFirstTwoBlocksAndPeers(t *testing.T) {
testBcR := newTestBcR()
tests := []struct {
name string
pool *BlockPool
firstWanted int64
secondWanted int64
errWanted error
}{
{
name: "both blocks missing",
pool: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{15: {"P1", true}, 16: {"P2", true}}),
errWanted: errMissingBlock,
},
{
name: "second block missing",
pool: makeBlockPool(testBcR, 15,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{15: {"P1", true}, 18: {"P2", true}}),
firstWanted: 15,
errWanted: errMissingBlock,
},
{
name: "first block missing",
pool: makeBlockPool(testBcR, 15,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{16: {"P2", true}, 18: {"P2", true}}),
secondWanted: 16,
errWanted: errMissingBlock,
},
{
name: "both blocks present",
pool: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{10: {"P1", true}, 11: {"P2", true}}),
firstWanted: 10,
secondWanted: 11,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
pool := tt.pool
gotFirst, gotSecond, err := pool.FirstTwoBlocksAndPeers()
assert.Equal(t, tt.errWanted, err)
if tt.firstWanted != 0 {
peer := pool.blocks[tt.firstWanted]
block := pool.peers[peer].blocks[tt.firstWanted]
assert.Equal(t, block, gotFirst.block,
"BlockPool.FirstTwoBlocksAndPeers() gotFirst = %v, want %v",
tt.firstWanted, gotFirst.block.Height)
}
if tt.secondWanted != 0 {
peer := pool.blocks[tt.secondWanted]
block := pool.peers[peer].blocks[tt.secondWanted]
assert.Equal(t, block, gotSecond.block,
"BlockPool.FirstTwoBlocksAndPeers() gotFirst = %v, want %v",
tt.secondWanted, gotSecond.block.Height)
}
})
}
}
func TestBlockPoolInvalidateFirstTwoBlocks(t *testing.T) {
testBcR := newTestBcR()
tests := []struct {
name string
pool *BlockPool
poolWanted *BlockPool
}{
{
name: "both blocks missing",
pool: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{15: {"P1", true}, 16: {"P2", true}}),
poolWanted: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{15: {"P1", true}, 16: {"P2", true}}),
},
{
name: "second block missing",
pool: makeBlockPool(testBcR, 15,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{15: {"P1", true}, 18: {"P2", true}}),
poolWanted: makeBlockPool(testBcR, 15,
[]BpPeer{{ID: "P2", Height: 100}},
map[int64]tPBlocks{18: {"P2", true}}),
},
{
name: "first block missing",
pool: makeBlockPool(testBcR, 15,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{18: {"P1", true}, 16: {"P2", true}}),
poolWanted: makeBlockPool(testBcR, 15,
[]BpPeer{{ID: "P1", Height: 100}},
map[int64]tPBlocks{18: {"P1", true}}),
},
{
name: "both blocks present",
pool: makeBlockPool(testBcR, 10,
[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
map[int64]tPBlocks{10: {"P1", true}, 11: {"P2", true}}),
poolWanted: makeBlockPool(testBcR, 10,
[]BpPeer{},
map[int64]tPBlocks{}),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
tt.pool.InvalidateFirstTwoBlocks(errNoPeerResponse)
assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
})
}
}
func TestProcessedCurrentHeightBlock(t *testing.T) {
testBcR := newTestBcR()
tests := []struct {
name string
pool *BlockPool
poolWanted *BlockPool
}{
{
name: "one peer",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}},
map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", true}}),
poolWanted: makeBlockPool(testBcR, 101, []BpPeer{{ID: "P1", Height: 120}},
map[int64]tPBlocks{101: {"P1", true}}),
},
{
name: "multiple peers",
pool: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
map[int64]tPBlocks{
100: {"P1", true}, 104: {"P1", true}, 105: {"P1", false},
101: {"P2", true}, 103: {"P2", false},
102: {"P3", true}, 106: {"P3", true}}),
poolWanted: makeBlockPool(testBcR, 101,
[]BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
map[int64]tPBlocks{
104: {"P1", true}, 105: {"P1", false},
101: {"P2", true}, 103: {"P2", false},
102: {"P3", true}, 106: {"P3", true}}),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
tt.pool.ProcessedCurrentHeightBlock()
assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
})
}
}
func TestRemovePeerAtCurrentHeight(t *testing.T) {
testBcR := newTestBcR()
tests := []struct {
name string
pool *BlockPool
poolWanted *BlockPool
}{
{
name: "one peer, remove peer for block at H",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}},
map[int64]tPBlocks{100: {"P1", false}, 101: {"P1", true}}),
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
},
{
name: "one peer, remove peer for block at H+1",
pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}},
map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", false}}),
poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
},
{
name: "multiple peers, remove peer for block at H",
pool: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
map[int64]tPBlocks{
100: {"P1", false}, 104: {"P1", true}, 105: {"P1", false},
101: {"P2", true}, 103: {"P2", false},
102: {"P3", true}, 106: {"P3", true}}),
poolWanted: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
map[int64]tPBlocks{
101: {"P2", true}, 103: {"P2", false},
102: {"P3", true}, 106: {"P3", true}}),
},
{
name: "multiple peers, remove peer for block at H+1",
pool: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
map[int64]tPBlocks{
100: {"P1", true}, 104: {"P1", true}, 105: {"P1", false},
101: {"P2", false}, 103: {"P2", false},
102: {"P3", true}, 106: {"P3", true}}),
poolWanted: makeBlockPool(testBcR, 100,
[]BpPeer{{ID: "P1", Height: 120}, {ID: "P3", Height: 130}},
map[int64]tPBlocks{
100: {"P1", true}, 104: {"P1", true}, 105: {"P1", false},
102: {"P3", true}, 106: {"P3", true}}),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
tt.pool.RemovePeerAtCurrentHeights(errNoPeerResponse)
assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
})
}
}

View File

@@ -1,575 +0,0 @@
package v1
import (
"fmt"
"reflect"
"time"
"github.com/tendermint/tendermint/behaviour" //nolint:misspell
bc "github.com/tendermint/tendermint/blockchain"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
)
const (
// BlockchainChannel is a channel for blocks and status updates (`BlockStore` height)
BlockchainChannel = byte(0x40)
trySyncIntervalMS = 10
trySendIntervalMS = 10
// ask for best height every 10s
statusUpdateIntervalSeconds = 10
)
var (
// Maximum number of requests that can be pending per peer, i.e. for which requests have been sent but blocks
// have not been received.
maxRequestsPerPeer = 20
// Maximum number of block requests for the reactor, pending or for which blocks have been received.
maxNumRequests = 64
)
type consensusReactor interface {
// for when we switch from blockchain reactor and fast sync to
// the consensus machine
SwitchToConsensus(state sm.State, skipWAL bool)
}
// BlockchainReactor handles long-term catchup syncing.
type BlockchainReactor struct {
p2p.BaseReactor
initialState sm.State // immutable
state sm.State
blockExec *sm.BlockExecutor
store *store.BlockStore
fastSync bool
stateSynced bool
fsm *BcReactorFSM
blocksSynced uint64
// Receive goroutine forwards messages to this channel to be processed in the context of the poolRoutine.
messagesForFSMCh chan bcReactorMessage
// Switch goroutine may send RemovePeer to the blockchain reactor. This is an error message that is relayed
// to this channel to be processed in the context of the poolRoutine.
errorsForFSMCh chan bcReactorMessage
// This channel is used by the FSM and indirectly the block pool to report errors to the blockchain reactor and
// the switch.
eventsFromFSMCh chan bcFsmMessage
swReporter *behaviour.SwitchReporter
}
// NewBlockchainReactor returns new reactor instance.
func NewBlockchainReactor(state sm.State, blockExec *sm.BlockExecutor, store *store.BlockStore,
fastSync bool) *BlockchainReactor {
if state.LastBlockHeight != store.Height() {
panic(fmt.Sprintf("state (%v) and store (%v) height mismatch", state.LastBlockHeight,
store.Height()))
}
const capacity = 1000
eventsFromFSMCh := make(chan bcFsmMessage, capacity)
messagesForFSMCh := make(chan bcReactorMessage, capacity)
errorsForFSMCh := make(chan bcReactorMessage, capacity)
startHeight := store.Height() + 1
if startHeight == 1 {
startHeight = state.InitialHeight
}
bcR := &BlockchainReactor{
initialState: state,
state: state,
blockExec: blockExec,
fastSync: fastSync,
store: store,
messagesForFSMCh: messagesForFSMCh,
eventsFromFSMCh: eventsFromFSMCh,
errorsForFSMCh: errorsForFSMCh,
}
fsm := NewFSM(startHeight, bcR)
bcR.fsm = fsm
bcR.BaseReactor = *p2p.NewBaseReactor("BlockchainReactor", bcR)
// bcR.swReporter = behavior.NewSwitchReporter(bcR.BaseReactor.Switch)
return bcR
}
// bcReactorMessage is used by the reactor to send messages to the FSM.
type bcReactorMessage struct {
event bReactorEvent
data bReactorEventData
}
type bFsmEvent uint
const (
// message type events
peerErrorEv = iota + 1
syncFinishedEv
)
type bFsmEventData struct {
peerID p2p.ID
err error
}
// bcFsmMessage is used by the FSM to send messages to the reactor
type bcFsmMessage struct {
event bFsmEvent
data bFsmEventData
}
// SetLogger implements service.Service by setting the logger on reactor and pool.
func (bcR *BlockchainReactor) SetLogger(l log.Logger) {
bcR.BaseService.Logger = l
bcR.fsm.SetLogger(l)
}
// OnStart implements service.Service.
func (bcR *BlockchainReactor) OnStart() error {
bcR.swReporter = behaviour.NewSwitchReporter(bcR.BaseReactor.Switch)
if bcR.fastSync {
go bcR.poolRoutine()
}
return nil
}
// OnStop implements service.Service.
func (bcR *BlockchainReactor) OnStop() {
_ = bcR.Stop()
}
// SwitchToFastSync is called by the state sync reactor when switching to fast sync.
func (bcR *BlockchainReactor) SwitchToFastSync(state sm.State) error {
bcR.fastSync = true
bcR.initialState = state
bcR.state = state
bcR.stateSynced = true
bcR.fsm = NewFSM(state.LastBlockHeight+1, bcR)
bcR.fsm.SetLogger(bcR.Logger)
go bcR.poolRoutine()
return nil
}
// GetChannels implements Reactor
func (bcR *BlockchainReactor) GetChannels() []*p2p.ChannelDescriptor {
return []*p2p.ChannelDescriptor{
{
ID: BlockchainChannel,
Priority: 10,
SendQueueCapacity: 2000,
RecvBufferCapacity: 50 * 4096,
RecvMessageCapacity: bc.MaxMsgSize,
},
}
}
// AddPeer implements Reactor by sending our state to peer.
func (bcR *BlockchainReactor) AddPeer(peer p2p.Peer) {
msgBytes, err := bc.EncodeMsg(&bcproto.StatusResponse{
Base: bcR.store.Base(),
Height: bcR.store.Height(),
})
if err != nil {
bcR.Logger.Error("could not convert msg to protobuf", "err", err)
return
}
peer.Send(BlockchainChannel, msgBytes)
// it's OK if send fails. will try later in poolRoutine
// peer is added to the pool once we receive the first
// bcStatusResponseMessage from the peer and call pool.updatePeer()
}
// sendBlockToPeer loads a block and sends it to the requesting peer.
// If the block doesn't exist a bcNoBlockResponseMessage is sent.
// If all nodes are honest, no node should be requesting for a block that doesn't exist.
func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest,
src p2p.Peer) (queued bool) {
block := bcR.store.LoadBlock(msg.Height)
if block != nil {
pbbi, err := block.ToProto()
if err != nil {
bcR.Logger.Error("Could not send block message to peer", "err", err)
return false
}
msgBytes, err := bc.EncodeMsg(&bcproto.BlockResponse{Block: pbbi})
if err != nil {
bcR.Logger.Error("unable to marshal msg", "err", err)
return false
}
return src.TrySend(BlockchainChannel, msgBytes)
}
bcR.Logger.Info("peer asking for a block we don't have", "src", src, "height", msg.Height)
msgBytes, err := bc.EncodeMsg(&bcproto.NoBlockResponse{Height: msg.Height})
if err != nil {
bcR.Logger.Error("unable to marshal msg", "err", err)
return false
}
return src.TrySend(BlockchainChannel, msgBytes)
}
func (bcR *BlockchainReactor) sendStatusResponseToPeer(msg *bcproto.StatusRequest, src p2p.Peer) (queued bool) {
msgBytes, err := bc.EncodeMsg(&bcproto.StatusResponse{
Base: bcR.store.Base(),
Height: bcR.store.Height(),
})
if err != nil {
bcR.Logger.Error("unable to marshal msg", "err", err)
return false
}
return src.TrySend(BlockchainChannel, msgBytes)
}
// RemovePeer implements Reactor by removing peer from the pool.
func (bcR *BlockchainReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
msgData := bcReactorMessage{
event: peerRemoveEv,
data: bReactorEventData{
peerID: peer.ID(),
err: errSwitchRemovesPeer,
},
}
bcR.errorsForFSMCh <- msgData
}
// Receive implements Reactor by handling 4 types of messages (look below).
func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
msg, err := bc.DecodeMsg(msgBytes)
if err != nil {
bcR.Logger.Error("error decoding message", "src", src, "chId", chID, "err", err)
_ = bcR.swReporter.Report(behaviour.BadMessage(src.ID(), err.Error()))
return
}
if err = bc.ValidateMsg(msg); err != nil {
bcR.Logger.Error("peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
_ = bcR.swReporter.Report(behaviour.BadMessage(src.ID(), err.Error()))
return
}
bcR.Logger.Debug("Receive", "src", src, "chID", chID, "msg", msg)
switch msg := msg.(type) {
case *bcproto.BlockRequest:
if queued := bcR.sendBlockToPeer(msg, src); !queued {
// Unfortunately not queued since the queue is full.
bcR.Logger.Error("Could not send block message to peer", "src", src, "height", msg.Height)
}
case *bcproto.StatusRequest:
// Send peer our state.
if queued := bcR.sendStatusResponseToPeer(msg, src); !queued {
// Unfortunately not queued since the queue is full.
bcR.Logger.Error("Could not send status message to peer", "src", src)
}
case *bcproto.BlockResponse:
bi, err := types.BlockFromProto(msg.Block)
if err != nil {
bcR.Logger.Error("error transition block from protobuf", "err", err)
return
}
msgForFSM := bcReactorMessage{
event: blockResponseEv,
data: bReactorEventData{
peerID: src.ID(),
height: bi.Height,
block: bi,
length: len(msgBytes),
},
}
bcR.Logger.Info("Received", "src", src, "height", bi.Height)
bcR.messagesForFSMCh <- msgForFSM
case *bcproto.NoBlockResponse:
msgForFSM := bcReactorMessage{
event: noBlockResponseEv,
data: bReactorEventData{
peerID: src.ID(),
height: msg.Height,
},
}
bcR.Logger.Debug("Peer does not have requested block", "peer", src, "height", msg.Height)
bcR.messagesForFSMCh <- msgForFSM
case *bcproto.StatusResponse:
// Got a peer status. Unverified.
msgForFSM := bcReactorMessage{
event: statusResponseEv,
data: bReactorEventData{
peerID: src.ID(),
height: msg.Height,
length: len(msgBytes),
},
}
bcR.messagesForFSMCh <- msgForFSM
default:
bcR.Logger.Error(fmt.Sprintf("unknown message type %v", reflect.TypeOf(msg)))
}
}
// processBlocksRoutine processes blocks until signlaed to stop over the stopProcessing channel
func (bcR *BlockchainReactor) processBlocksRoutine(stopProcessing chan struct{}) {
processReceivedBlockTicker := time.NewTicker(trySyncIntervalMS * time.Millisecond)
doProcessBlockCh := make(chan struct{}, 1)
lastHundred := time.Now()
lastRate := 0.0
ForLoop:
for {
select {
case <-stopProcessing:
bcR.Logger.Info("finishing block execution")
break ForLoop
case <-processReceivedBlockTicker.C: // try to execute blocks
select {
case doProcessBlockCh <- struct{}{}:
default:
}
case <-doProcessBlockCh:
for {
err := bcR.processBlock()
if err == errMissingBlock {
break
}
// Notify FSM of block processing result.
msgForFSM := bcReactorMessage{
event: processedBlockEv,
data: bReactorEventData{
err: err,
},
}
_ = bcR.fsm.Handle(&msgForFSM)
if err != nil {
break
}
bcR.blocksSynced++
if bcR.blocksSynced%100 == 0 {
lastRate = 0.9*lastRate + 0.1*(100/time.Since(lastHundred).Seconds())
height, maxPeerHeight := bcR.fsm.Status()
bcR.Logger.Info("Fast Sync Rate", "height", height,
"max_peer_height", maxPeerHeight, "blocks/s", lastRate)
lastHundred = time.Now()
}
}
}
}
}
// poolRoutine receives and handles messages from the Receive() routine and from the FSM.
func (bcR *BlockchainReactor) poolRoutine() {
bcR.fsm.Start()
sendBlockRequestTicker := time.NewTicker(trySendIntervalMS * time.Millisecond)
statusUpdateTicker := time.NewTicker(statusUpdateIntervalSeconds * time.Second)
stopProcessing := make(chan struct{}, 1)
go bcR.processBlocksRoutine(stopProcessing)
ForLoop:
for {
select {
case <-sendBlockRequestTicker.C:
if !bcR.fsm.NeedsBlocks() {
continue
}
_ = bcR.fsm.Handle(&bcReactorMessage{
event: makeRequestsEv,
data: bReactorEventData{
maxNumRequests: maxNumRequests}})
case <-statusUpdateTicker.C:
// Ask for status updates.
go bcR.sendStatusRequest()
case msg := <-bcR.messagesForFSMCh:
// Sent from the Receive() routine when status (statusResponseEv) and
// block (blockResponseEv) response events are received
_ = bcR.fsm.Handle(&msg)
case msg := <-bcR.errorsForFSMCh:
// Sent from the switch.RemovePeer() routine (RemovePeerEv) and
// FSM state timer expiry routine (stateTimeoutEv).
_ = bcR.fsm.Handle(&msg)
case msg := <-bcR.eventsFromFSMCh:
switch msg.event {
case syncFinishedEv:
stopProcessing <- struct{}{}
// Sent from the FSM when it enters finished state.
break ForLoop
case peerErrorEv:
// Sent from the FSM when it detects peer error
bcR.reportPeerErrorToSwitch(msg.data.err, msg.data.peerID)
if msg.data.err == errNoPeerResponse {
// Sent from the peer timeout handler routine
_ = bcR.fsm.Handle(&bcReactorMessage{
event: peerRemoveEv,
data: bReactorEventData{
peerID: msg.data.peerID,
err: msg.data.err,
},
})
}
// else {
// For slow peers, or errors due to blocks received from wrong peer
// the FSM had already removed the peers
// }
default:
bcR.Logger.Error("Event from FSM not supported", "type", msg.event)
}
case <-bcR.Quit():
break ForLoop
}
}
}
func (bcR *BlockchainReactor) reportPeerErrorToSwitch(err error, peerID p2p.ID) {
peer := bcR.Switch.Peers().Get(peerID)
if peer != nil {
_ = bcR.swReporter.Report(behaviour.BadMessage(peerID, err.Error()))
}
}
func (bcR *BlockchainReactor) processBlock() error {
first, second, err := bcR.fsm.FirstTwoBlocks()
if err != nil {
// We need both to sync the first block.
return err
}
chainID := bcR.initialState.ChainID
firstParts, err := first.MakePartSet(types.BlockPartSizeBytes)
if err != nil {
bcR.Logger.Error("failed to make ",
"height", first.Height,
"err", err.Error())
return err
}
firstPartSetHeader := firstParts.Header()
firstID := types.BlockID{Hash: first.Hash(), PartSetHeader: firstPartSetHeader}
// Finally, verify the first block using the second's commit
// NOTE: we can probably make this more efficient, but note that calling
// first.Hash() doesn't verify the tx contents, so MakePartSet() is
// currently necessary.
err = bcR.state.Validators.VerifyCommitLight(chainID, firstID, first.Height, second.LastCommit)
if err != nil {
bcR.Logger.Error("error during commit verification", "err", err,
"first", first.Height, "second", second.Height)
return errBlockVerificationFailure
}
bcR.store.SaveBlock(first, firstParts, second.LastCommit)
bcR.state, _, err = bcR.blockExec.ApplyBlock(bcR.state, firstID, first)
if err != nil {
panic(fmt.Sprintf("failed to process committed block (%d:%X): %v", first.Height, first.Hash(), err))
}
return nil
}
// Implements bcRNotifier
// sendStatusRequest broadcasts `BlockStore` height.
func (bcR *BlockchainReactor) sendStatusRequest() {
msgBytes, err := bc.EncodeMsg(&bcproto.StatusRequest{})
if err != nil {
panic(err)
}
bcR.Switch.Broadcast(BlockchainChannel, msgBytes)
}
// Implements bcRNotifier
// BlockRequest sends `BlockRequest` height.
func (bcR *BlockchainReactor) sendBlockRequest(peerID p2p.ID, height int64) error {
peer := bcR.Switch.Peers().Get(peerID)
if peer == nil {
return errNilPeerForBlockRequest
}
msgBytes, err := bc.EncodeMsg(&bcproto.BlockRequest{Height: height})
if err != nil {
return err
}
queued := peer.TrySend(BlockchainChannel, msgBytes)
if !queued {
return errSendQueueFull
}
return nil
}
// Implements bcRNotifier
func (bcR *BlockchainReactor) switchToConsensus() {
conR, ok := bcR.Switch.Reactor("CONSENSUS").(consensusReactor)
if ok {
conR.SwitchToConsensus(bcR.state, bcR.blocksSynced > 0 || bcR.stateSynced)
bcR.eventsFromFSMCh <- bcFsmMessage{event: syncFinishedEv}
}
// else {
// Should only happen during testing.
// }
}
// Implements bcRNotifier
// Called by FSM and pool:
// - pool calls when it detects slow peer or when peer times out
// - FSM calls when:
// - adding a block (addBlock) fails
// - reactor processing of a block reports failure and FSM sends back the peers of first and second blocks
func (bcR *BlockchainReactor) sendPeerError(err error, peerID p2p.ID) {
bcR.Logger.Info("sendPeerError:", "peer", peerID, "error", err)
msgData := bcFsmMessage{
event: peerErrorEv,
data: bFsmEventData{
peerID: peerID,
err: err,
},
}
bcR.eventsFromFSMCh <- msgData
}
// Implements bcRNotifier
func (bcR *BlockchainReactor) resetStateTimer(name string, timer **time.Timer, timeout time.Duration) {
if timer == nil {
panic("nil timer pointer parameter")
}
if *timer == nil {
*timer = time.AfterFunc(timeout, func() {
msg := bcReactorMessage{
event: stateTimeoutEv,
data: bReactorEventData{
stateName: name,
},
}
bcR.errorsForFSMCh <- msg
})
} else {
(*timer).Reset(timeout)
}
}

View File

@@ -1,462 +0,0 @@
package v1
import (
"errors"
"fmt"
"sync"
"time"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
// Blockchain Reactor State
type bcReactorFSMState struct {
name string
// called when transitioning out of current state
handle func(*BcReactorFSM, bReactorEvent, bReactorEventData) (next *bcReactorFSMState, err error)
// called when entering the state
enter func(fsm *BcReactorFSM)
// timeout to ensure FSM is not stuck in a state forever
// the timer is owned and run by the fsm instance
timeout time.Duration
}
func (s *bcReactorFSMState) String() string {
return s.name
}
// BcReactorFSM is the datastructure for the Blockchain Reactor State Machine
type BcReactorFSM struct {
logger log.Logger
mtx sync.Mutex
startTime time.Time
state *bcReactorFSMState
stateTimer *time.Timer
pool *BlockPool
// interface used to call the Blockchain reactor to send StatusRequest, BlockRequest, reporting errors, etc.
toBcR bcReactor
}
// NewFSM creates a new reactor FSM.
func NewFSM(height int64, toBcR bcReactor) *BcReactorFSM {
return &BcReactorFSM{
state: unknown,
startTime: time.Now(),
pool: NewBlockPool(height, toBcR),
toBcR: toBcR,
}
}
// bReactorEventData is part of the message sent by the reactor to the FSM and used by the state handlers.
type bReactorEventData struct {
peerID p2p.ID
err error // for peer error: timeout, slow; for processed block event if error occurred
base int64 // for status response
height int64 // for status response; for processed block event
block *types.Block // for block response
stateName string // for state timeout events
length int // for block response event, length of received block, used to detect slow peers
maxNumRequests int // for request needed event, maximum number of pending requests
}
// Blockchain Reactor Events (the input to the state machine)
type bReactorEvent uint
const (
// message type events
startFSMEv = iota + 1
statusResponseEv
blockResponseEv
noBlockResponseEv
processedBlockEv
makeRequestsEv
stopFSMEv
// other events
peerRemoveEv = iota + 256
stateTimeoutEv
)
func (msg *bcReactorMessage) String() string {
var dataStr string
switch msg.event {
case startFSMEv:
dataStr = ""
case statusResponseEv:
dataStr = fmt.Sprintf("peer=%v base=%v height=%v", msg.data.peerID, msg.data.base, msg.data.height)
case blockResponseEv:
dataStr = fmt.Sprintf("peer=%v block.height=%v length=%v",
msg.data.peerID, msg.data.block.Height, msg.data.length)
case noBlockResponseEv:
dataStr = fmt.Sprintf("peer=%v requested height=%v",
msg.data.peerID, msg.data.height)
case processedBlockEv:
dataStr = fmt.Sprintf("error=%v", msg.data.err)
case makeRequestsEv:
dataStr = ""
case stopFSMEv:
dataStr = ""
case peerRemoveEv:
dataStr = fmt.Sprintf("peer: %v is being removed by the switch", msg.data.peerID)
case stateTimeoutEv:
dataStr = fmt.Sprintf("state=%v", msg.data.stateName)
default:
dataStr = "cannot interpret message data"
}
return fmt.Sprintf("%v: %v", msg.event, dataStr)
}
func (ev bReactorEvent) String() string {
switch ev {
case startFSMEv:
return "startFSMEv"
case statusResponseEv:
return "statusResponseEv"
case blockResponseEv:
return "blockResponseEv"
case noBlockResponseEv:
return "noBlockResponseEv"
case processedBlockEv:
return "processedBlockEv"
case makeRequestsEv:
return "makeRequestsEv"
case stopFSMEv:
return "stopFSMEv"
case peerRemoveEv:
return "peerRemoveEv"
case stateTimeoutEv:
return "stateTimeoutEv"
default:
return "event unknown"
}
}
// states
var (
unknown *bcReactorFSMState
waitForPeer *bcReactorFSMState
waitForBlock *bcReactorFSMState
finished *bcReactorFSMState
)
// timeouts for state timers
const (
waitForPeerTimeout = 3 * time.Second
waitForBlockAtCurrentHeightTimeout = 10 * time.Second
)
// errors
var (
// internal to the package
errNoErrorFinished = errors.New("fast sync is finished")
errInvalidEvent = errors.New("invalid event in current state")
errMissingBlock = errors.New("missing blocks")
errNilPeerForBlockRequest = errors.New("peer for block request does not exist in the switch")
errSendQueueFull = errors.New("block request not made, send-queue is full")
errPeerTooShort = errors.New("peer height too low, old peer removed/ new peer not added")
errSwitchRemovesPeer = errors.New("switch is removing peer")
errTimeoutEventWrongState = errors.New("timeout event for a state different than the current one")
errNoTallerPeer = errors.New("fast sync timed out on waiting for a peer taller than this node")
// reported eventually to the switch
// handle return
errPeerLowersItsHeight = errors.New("fast sync peer reports a height lower than previous")
// handle return
errNoPeerResponseForCurrentHeights = errors.New("fast sync timed out on peer block response for current heights")
errNoPeerResponse = errors.New("fast sync timed out on peer block response") // xx
errBadDataFromPeer = errors.New("fast sync received block from wrong peer or block is bad") // xx
errDuplicateBlock = errors.New("fast sync received duplicate block from peer")
errBlockVerificationFailure = errors.New("fast sync block verification failure") // xx
errSlowPeer = errors.New("fast sync peer is not sending us data fast enough") // xx
)
func init() {
unknown = &bcReactorFSMState{
name: "unknown",
handle: func(fsm *BcReactorFSM, ev bReactorEvent, data bReactorEventData) (*bcReactorFSMState, error) {
switch ev {
case startFSMEv:
// Broadcast Status message. Currently doesn't return non-nil error.
fsm.toBcR.sendStatusRequest()
return waitForPeer, nil
case stopFSMEv:
return finished, errNoErrorFinished
default:
return unknown, errInvalidEvent
}
},
}
waitForPeer = &bcReactorFSMState{
name: "waitForPeer",
timeout: waitForPeerTimeout,
enter: func(fsm *BcReactorFSM) {
// Stop when leaving the state.
fsm.resetStateTimer()
},
handle: func(fsm *BcReactorFSM, ev bReactorEvent, data bReactorEventData) (*bcReactorFSMState, error) {
switch ev {
case stateTimeoutEv:
if data.stateName != "waitForPeer" {
fsm.logger.Error("received a state timeout event for different state",
"state", data.stateName)
return waitForPeer, errTimeoutEventWrongState
}
// There was no statusResponse received from any peer.
// Should we send status request again?
return finished, errNoTallerPeer
case statusResponseEv:
if err := fsm.pool.UpdatePeer(data.peerID, data.base, data.height); err != nil {
if fsm.pool.NumPeers() == 0 {
return waitForPeer, err
}
}
if fsm.stateTimer != nil {
fsm.stateTimer.Stop()
}
return waitForBlock, nil
case stopFSMEv:
if fsm.stateTimer != nil {
fsm.stateTimer.Stop()
}
return finished, errNoErrorFinished
default:
return waitForPeer, errInvalidEvent
}
},
}
waitForBlock = &bcReactorFSMState{
name: "waitForBlock",
timeout: waitForBlockAtCurrentHeightTimeout,
enter: func(fsm *BcReactorFSM) {
// Stop when leaving the state.
fsm.resetStateTimer()
},
handle: func(fsm *BcReactorFSM, ev bReactorEvent, data bReactorEventData) (*bcReactorFSMState, error) {
switch ev {
case statusResponseEv:
err := fsm.pool.UpdatePeer(data.peerID, data.base, data.height)
if fsm.pool.NumPeers() == 0 {
return waitForPeer, err
}
if fsm.pool.ReachedMaxHeight() {
return finished, err
}
return waitForBlock, err
case blockResponseEv:
fsm.logger.Debug("blockResponseEv", "H", data.block.Height)
err := fsm.pool.AddBlock(data.peerID, data.block, data.length)
if err != nil {
// A block was received that was unsolicited, from unexpected peer, or that we already have it.
// Ignore block, remove peer and send error to switch.
fsm.pool.RemovePeer(data.peerID, err)
fsm.toBcR.sendPeerError(err, data.peerID)
}
if fsm.pool.NumPeers() == 0 {
return waitForPeer, err
}
return waitForBlock, err
case noBlockResponseEv:
fsm.logger.Error("peer does not have requested block", "peer", data.peerID)
return waitForBlock, nil
case processedBlockEv:
if data.err != nil {
first, second, _ := fsm.pool.FirstTwoBlocksAndPeers()
fsm.logger.Error("error processing block", "err", data.err,
"first", first.block.Height, "second", second.block.Height)
fsm.logger.Error("send peer error for", "peer", first.peer.ID)
fsm.toBcR.sendPeerError(data.err, first.peer.ID)
fsm.logger.Error("send peer error for", "peer", second.peer.ID)
fsm.toBcR.sendPeerError(data.err, second.peer.ID)
// Remove the first two blocks. This will also remove the peers
fsm.pool.InvalidateFirstTwoBlocks(data.err)
} else {
fsm.pool.ProcessedCurrentHeightBlock()
// Since we advanced one block reset the state timer
fsm.resetStateTimer()
}
// Both cases above may result in achieving maximum height.
if fsm.pool.ReachedMaxHeight() {
return finished, nil
}
return waitForBlock, data.err
case peerRemoveEv:
// This event is sent by the switch to remove disconnected and errored peers.
fsm.pool.RemovePeer(data.peerID, data.err)
if fsm.pool.NumPeers() == 0 {
return waitForPeer, nil
}
if fsm.pool.ReachedMaxHeight() {
return finished, nil
}
return waitForBlock, nil
case makeRequestsEv:
fsm.makeNextRequests(data.maxNumRequests)
return waitForBlock, nil
case stateTimeoutEv:
if data.stateName != "waitForBlock" {
fsm.logger.Error("received a state timeout event for different state",
"state", data.stateName)
return waitForBlock, errTimeoutEventWrongState
}
// We haven't received the block at current height or height+1. Remove peer.
fsm.pool.RemovePeerAtCurrentHeights(errNoPeerResponseForCurrentHeights)
fsm.resetStateTimer()
if fsm.pool.NumPeers() == 0 {
return waitForPeer, errNoPeerResponseForCurrentHeights
}
if fsm.pool.ReachedMaxHeight() {
return finished, nil
}
return waitForBlock, errNoPeerResponseForCurrentHeights
case stopFSMEv:
if fsm.stateTimer != nil {
fsm.stateTimer.Stop()
}
return finished, errNoErrorFinished
default:
return waitForBlock, errInvalidEvent
}
},
}
finished = &bcReactorFSMState{
name: "finished",
enter: func(fsm *BcReactorFSM) {
fsm.logger.Info("Time to switch to consensus reactor!", "height", fsm.pool.Height)
fsm.toBcR.switchToConsensus()
fsm.cleanup()
},
handle: func(fsm *BcReactorFSM, ev bReactorEvent, data bReactorEventData) (*bcReactorFSMState, error) {
return finished, nil
},
}
}
// Interface used by FSM for sending Block and Status requests,
// informing of peer errors and state timeouts
// Implemented by BlockchainReactor and tests
type bcReactor interface {
sendStatusRequest()
sendBlockRequest(peerID p2p.ID, height int64) error
sendPeerError(err error, peerID p2p.ID)
resetStateTimer(name string, timer **time.Timer, timeout time.Duration)
switchToConsensus()
}
// SetLogger sets the FSM logger.
func (fsm *BcReactorFSM) SetLogger(l log.Logger) {
fsm.logger = l
fsm.pool.SetLogger(l)
}
// Start starts the FSM.
func (fsm *BcReactorFSM) Start() {
_ = fsm.Handle(&bcReactorMessage{event: startFSMEv})
}
// Handle processes messages and events sent to the FSM.
func (fsm *BcReactorFSM) Handle(msg *bcReactorMessage) error {
fsm.mtx.Lock()
defer fsm.mtx.Unlock()
fsm.logger.Debug("FSM received", "event", msg, "state", fsm.state)
if fsm.state == nil {
fsm.state = unknown
}
next, err := fsm.state.handle(fsm, msg.event, msg.data)
if err != nil {
fsm.logger.Error("FSM event handler returned", "err", err,
"state", fsm.state, "event", msg.event)
}
oldState := fsm.state.name
fsm.transition(next)
if oldState != fsm.state.name {
fsm.logger.Info("FSM changed state", "new_state", fsm.state)
}
return err
}
func (fsm *BcReactorFSM) transition(next *bcReactorFSMState) {
if next == nil {
return
}
if fsm.state != next {
fsm.state = next
if next.enter != nil {
next.enter(fsm)
}
}
}
// Called when entering an FSM state in order to detect lack of progress in the state machine.
// Note the use of the 'bcr' interface to facilitate testing without timer expiring.
func (fsm *BcReactorFSM) resetStateTimer() {
fsm.toBcR.resetStateTimer(fsm.state.name, &fsm.stateTimer, fsm.state.timeout)
}
func (fsm *BcReactorFSM) isCaughtUp() bool {
return fsm.state == finished
}
func (fsm *BcReactorFSM) makeNextRequests(maxNumRequests int) {
fsm.pool.MakeNextRequests(maxNumRequests)
}
func (fsm *BcReactorFSM) cleanup() {
fsm.pool.Cleanup()
}
// NeedsBlocks checks if more block requests are required.
func (fsm *BcReactorFSM) NeedsBlocks() bool {
fsm.mtx.Lock()
defer fsm.mtx.Unlock()
return fsm.state.name == "waitForBlock" && fsm.pool.NeedsBlocks()
}
// FirstTwoBlocks returns the two blocks at pool height and height+1
func (fsm *BcReactorFSM) FirstTwoBlocks() (first, second *types.Block, err error) {
fsm.mtx.Lock()
defer fsm.mtx.Unlock()
firstBP, secondBP, err := fsm.pool.FirstTwoBlocksAndPeers()
if err == nil {
first = firstBP.block
second = secondBP.block
}
return
}
// Status returns the pool's height and the maximum peer height.
func (fsm *BcReactorFSM) Status() (height, maxPeerHeight int64) {
fsm.mtx.Lock()
defer fsm.mtx.Unlock()
return fsm.pool.Height, fsm.pool.MaxPeerHeight
}

View File

@@ -1,944 +0,0 @@
package v1
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/tendermint/tendermint/libs/log"
tmmath "github.com/tendermint/tendermint/libs/math"
tmrand "github.com/tendermint/tendermint/libs/rand"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
type lastBlockRequestT struct {
peerID p2p.ID
height int64
}
type lastPeerErrorT struct {
peerID p2p.ID
err error
}
// reactor for FSM testing
type testReactor struct {
logger log.Logger
fsm *BcReactorFSM
numStatusRequests int
numBlockRequests int
lastBlockRequest lastBlockRequestT
lastPeerError lastPeerErrorT
stateTimerStarts map[string]int
}
func sendEventToFSM(fsm *BcReactorFSM, ev bReactorEvent, data bReactorEventData) error {
return fsm.Handle(&bcReactorMessage{event: ev, data: data})
}
type fsmStepTestValues struct {
currentState string
event bReactorEvent
data bReactorEventData
wantErr error
wantState string
wantStatusReqSent bool
wantReqIncreased bool
wantNewBlocks []int64
wantRemovedPeers []p2p.ID
}
// ---------------------------------------------------------------------------
// helper test function for different FSM events, state and expected behavior
func sStopFSMEv(current, expected string) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
event: stopFSMEv,
wantState: expected,
wantErr: errNoErrorFinished}
}
func sUnknownFSMEv(current string) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
event: 1234,
wantState: current,
wantErr: errInvalidEvent}
}
func sStartFSMEv() fsmStepTestValues {
return fsmStepTestValues{
currentState: "unknown",
event: startFSMEv,
wantState: "waitForPeer",
wantStatusReqSent: true}
}
func sStateTimeoutEv(current, expected string, timedoutState string, wantErr error) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
event: stateTimeoutEv,
data: bReactorEventData{
stateName: timedoutState,
},
wantState: expected,
wantErr: wantErr,
}
}
func sProcessedBlockEv(current, expected string, reactorError error) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
event: processedBlockEv,
data: bReactorEventData{
err: reactorError,
},
wantState: expected,
wantErr: reactorError,
}
}
func sStatusEv(current, expected string, peerID p2p.ID, height int64, err error) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
event: statusResponseEv,
data: bReactorEventData{peerID: peerID, height: height},
wantState: expected,
wantErr: err}
}
func sMakeRequestsEv(current, expected string, maxPendingRequests int) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
event: makeRequestsEv,
data: bReactorEventData{maxNumRequests: maxPendingRequests},
wantState: expected,
wantReqIncreased: true,
}
}
func sMakeRequestsEvErrored(current, expected string,
maxPendingRequests int, err error, peersRemoved []p2p.ID) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
event: makeRequestsEv,
data: bReactorEventData{maxNumRequests: maxPendingRequests},
wantState: expected,
wantErr: err,
wantRemovedPeers: peersRemoved,
wantReqIncreased: true,
}
}
func sBlockRespEv(current, expected string, peerID p2p.ID, height int64, prevBlocks []int64) fsmStepTestValues {
txs := []types.Tx{types.Tx("foo"), types.Tx("bar")}
return fsmStepTestValues{
currentState: current,
event: blockResponseEv,
data: bReactorEventData{
peerID: peerID,
height: height,
block: types.MakeBlock(height, txs, nil, nil),
length: 100},
wantState: expected,
wantNewBlocks: append(prevBlocks, height),
}
}
func sBlockRespEvErrored(current, expected string,
peerID p2p.ID, height int64, prevBlocks []int64, wantErr error, peersRemoved []p2p.ID) fsmStepTestValues {
txs := []types.Tx{types.Tx("foo"), types.Tx("bar")}
return fsmStepTestValues{
currentState: current,
event: blockResponseEv,
data: bReactorEventData{
peerID: peerID,
height: height,
block: types.MakeBlock(height, txs, nil, nil),
length: 100},
wantState: expected,
wantErr: wantErr,
wantRemovedPeers: peersRemoved,
wantNewBlocks: prevBlocks,
}
}
func sPeerRemoveEv(current, expected string, peerID p2p.ID, err error, peersRemoved []p2p.ID) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
event: peerRemoveEv,
data: bReactorEventData{
peerID: peerID,
err: err,
},
wantState: expected,
wantRemovedPeers: peersRemoved,
}
}
// --------------------------------------------
func newTestReactor(height int64) *testReactor {
testBcR := &testReactor{logger: log.TestingLogger(), stateTimerStarts: make(map[string]int)}
testBcR.fsm = NewFSM(height, testBcR)
testBcR.fsm.SetLogger(testBcR.logger)
return testBcR
}
func fixBlockResponseEvStep(step *fsmStepTestValues, testBcR *testReactor) {
// There is currently no good way to know to which peer a block request was sent.
// So in some cases where it does not matter, before we simulate a block response
// we cheat and look where it is expected from.
if step.event == blockResponseEv {
height := step.data.height
peerID, ok := testBcR.fsm.pool.blocks[height]
if ok {
step.data.peerID = peerID
}
}
}
type testFields struct {
name string
startingHeight int64
maxRequestsPerPeer int
maxPendingRequests int
steps []fsmStepTestValues
}
func executeFSMTests(t *testing.T, tests []testFields, matchRespToReq bool) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
// Create test reactor
testBcR := newTestReactor(tt.startingHeight)
if tt.maxRequestsPerPeer != 0 {
maxRequestsPerPeer = tt.maxRequestsPerPeer
}
for _, step := range tt.steps {
step := step
assert.Equal(t, step.currentState, testBcR.fsm.state.name)
var heightBefore int64
if step.event == processedBlockEv && step.data.err == errBlockVerificationFailure {
heightBefore = testBcR.fsm.pool.Height
}
oldNumStatusRequests := testBcR.numStatusRequests
oldNumBlockRequests := testBcR.numBlockRequests
if matchRespToReq {
fixBlockResponseEvStep(&step, testBcR)
}
fsmErr := sendEventToFSM(testBcR.fsm, step.event, step.data)
assert.Equal(t, step.wantErr, fsmErr)
if step.wantStatusReqSent {
assert.Equal(t, oldNumStatusRequests+1, testBcR.numStatusRequests)
} else {
assert.Equal(t, oldNumStatusRequests, testBcR.numStatusRequests)
}
if step.wantReqIncreased {
assert.True(t, oldNumBlockRequests < testBcR.numBlockRequests)
} else {
assert.Equal(t, oldNumBlockRequests, testBcR.numBlockRequests)
}
for _, height := range step.wantNewBlocks {
_, err := testBcR.fsm.pool.BlockAndPeerAtHeight(height)
assert.Nil(t, err)
}
if step.event == processedBlockEv && step.data.err == errBlockVerificationFailure {
heightAfter := testBcR.fsm.pool.Height
assert.Equal(t, heightBefore, heightAfter)
firstAfter, err1 := testBcR.fsm.pool.BlockAndPeerAtHeight(testBcR.fsm.pool.Height)
secondAfter, err2 := testBcR.fsm.pool.BlockAndPeerAtHeight(testBcR.fsm.pool.Height + 1)
assert.NotNil(t, err1)
assert.NotNil(t, err2)
assert.Nil(t, firstAfter)
assert.Nil(t, secondAfter)
}
assert.Equal(t, step.wantState, testBcR.fsm.state.name)
if step.wantState == "finished" {
assert.True(t, testBcR.fsm.isCaughtUp())
}
}
})
}
}
func TestFSMBasic(t *testing.T) {
tests := []testFields{
{
name: "one block, one peer - TS2",
startingHeight: 1,
maxRequestsPerPeer: 2,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForBlock", "P1", 2, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 1, []int64{}),
sBlockRespEv("waitForBlock", "waitForBlock", "P2", 2, []int64{1}),
sProcessedBlockEv("waitForBlock", "finished", nil),
},
},
{
name: "multi block, multi peer - TS2",
startingHeight: 1,
maxRequestsPerPeer: 2,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForBlock", "P1", 4, nil),
sStatusEv("waitForBlock", "waitForBlock", "P2", 4, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 1, []int64{}),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 2, []int64{1}),
sBlockRespEv("waitForBlock", "waitForBlock", "P2", 3, []int64{1, 2}),
sBlockRespEv("waitForBlock", "waitForBlock", "P2", 4, []int64{1, 2, 3}),
sProcessedBlockEv("waitForBlock", "waitForBlock", nil),
sProcessedBlockEv("waitForBlock", "waitForBlock", nil),
sProcessedBlockEv("waitForBlock", "finished", nil),
},
},
}
executeFSMTests(t, tests, true)
}
func TestFSMBlockVerificationFailure(t *testing.T) {
tests := []testFields{
{
name: "block verification failure - TS2 variant",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1 and get blocks 1-3 from it
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 1, []int64{}),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 2, []int64{1}),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 3, []int64{1, 2}),
// add P2
sStatusEv("waitForBlock", "waitForBlock", "P2", 3, nil),
// process block failure, should remove P1 and all blocks
sProcessedBlockEv("waitForBlock", "waitForBlock", errBlockVerificationFailure),
// get blocks 1-3 from P2
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sBlockRespEv("waitForBlock", "waitForBlock", "P2", 1, []int64{}),
sBlockRespEv("waitForBlock", "waitForBlock", "P2", 2, []int64{1}),
sBlockRespEv("waitForBlock", "waitForBlock", "P2", 3, []int64{1, 2}),
// finish after processing blocks 1 and 2
sProcessedBlockEv("waitForBlock", "waitForBlock", nil),
sProcessedBlockEv("waitForBlock", "finished", nil),
},
},
}
executeFSMTests(t, tests, false)
}
func TestFSMBadBlockFromPeer(t *testing.T) {
tests := []testFields{
{
name: "block we haven't asked for",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1 and ask for blocks 1-3
sStatusEv("waitForPeer", "waitForBlock", "P1", 300, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
// blockResponseEv for height 100 should cause an error
sBlockRespEvErrored("waitForBlock", "waitForPeer",
"P1", 100, []int64{}, errMissingBlock, []p2p.ID{}),
},
},
{
name: "block we already have",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1 and get block 1
sStatusEv("waitForPeer", "waitForBlock", "P1", 100, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sBlockRespEv("waitForBlock", "waitForBlock",
"P1", 1, []int64{}),
// Get block 1 again. Since peer is removed together with block 1,
// the blocks present in the pool should be {}
sBlockRespEvErrored("waitForBlock", "waitForPeer",
"P1", 1, []int64{}, errDuplicateBlock, []p2p.ID{"P1"}),
},
},
{
name: "block from unknown peer",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1 and get block 1
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
// get block 1 from unknown peer P2
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sBlockRespEvErrored("waitForBlock", "waitForBlock",
"P2", 1, []int64{}, errBadDataFromPeer, []p2p.ID{"P2"}),
},
},
{
name: "block from wrong peer",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1, make requests for blocks 1-3 to P1
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
// add P2
sStatusEv("waitForBlock", "waitForBlock", "P2", 3, nil),
// receive block 1 from P2
sBlockRespEvErrored("waitForBlock", "waitForBlock",
"P2", 1, []int64{}, errBadDataFromPeer, []p2p.ID{"P2"}),
},
},
}
executeFSMTests(t, tests, false)
}
func TestFSMBlockAtCurrentHeightDoesNotArriveInTime(t *testing.T) {
tests := []testFields{
{
name: "block at current height undelivered - TS5",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1, get blocks 1 and 2, process block 1
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sBlockRespEv("waitForBlock", "waitForBlock",
"P1", 1, []int64{}),
sBlockRespEv("waitForBlock", "waitForBlock",
"P1", 2, []int64{1}),
sProcessedBlockEv("waitForBlock", "waitForBlock", nil),
// add P2
sStatusEv("waitForBlock", "waitForBlock", "P2", 3, nil),
// timeout on block 3, P1 should be removed
sStateTimeoutEv("waitForBlock", "waitForBlock", "waitForBlock", errNoPeerResponseForCurrentHeights),
// make requests and finish by receiving blocks 2 and 3 from P2
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sBlockRespEv("waitForBlock", "waitForBlock", "P2", 2, []int64{}),
sBlockRespEv("waitForBlock", "waitForBlock", "P2", 3, []int64{2}),
sProcessedBlockEv("waitForBlock", "finished", nil),
},
},
{
name: "block at current height undelivered, at maxPeerHeight after peer removal - TS3",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1, request blocks 1-3 from P1
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
// add P2 (tallest)
sStatusEv("waitForBlock", "waitForBlock", "P2", 30, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
// receive blocks 1-3 from P1
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 1, []int64{}),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 2, []int64{1}),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 3, []int64{1, 2}),
// process blocks at heights 1 and 2
sProcessedBlockEv("waitForBlock", "waitForBlock", nil),
sProcessedBlockEv("waitForBlock", "waitForBlock", nil),
// timeout on block at height 4
sStateTimeoutEv("waitForBlock", "finished", "waitForBlock", nil),
},
},
}
executeFSMTests(t, tests, true)
}
func TestFSMPeerRelatedEvents(t *testing.T) {
tests := []testFields{
{
name: "peer remove event with no blocks",
startingHeight: 1,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1, P2, P3
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sStatusEv("waitForBlock", "waitForBlock", "P2", 3, nil),
sStatusEv("waitForBlock", "waitForBlock", "P3", 3, nil),
// switch removes P2
sPeerRemoveEv("waitForBlock", "waitForBlock", "P2", errSwitchRemovesPeer, []p2p.ID{"P2"}),
},
},
{
name: "only peer removed while in waitForBlock state",
startingHeight: 100,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1
sStatusEv("waitForPeer", "waitForBlock", "P1", 200, nil),
// switch removes P1
sPeerRemoveEv("waitForBlock", "waitForPeer", "P1", errSwitchRemovesPeer, []p2p.ID{"P1"}),
},
},
{
name: "highest peer removed while in waitForBlock state, node reaches maxPeerHeight - TS4 ",
startingHeight: 100,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1 and make requests
sStatusEv("waitForPeer", "waitForBlock", "P1", 101, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
// add P2
sStatusEv("waitForBlock", "waitForBlock", "P2", 200, nil),
// get blocks 100 and 101 from P1 and process block at height 100
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 100, []int64{}),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 101, []int64{100}),
sProcessedBlockEv("waitForBlock", "waitForBlock", nil),
// switch removes peer P1, should be finished
sPeerRemoveEv("waitForBlock", "finished", "P2", errSwitchRemovesPeer, []p2p.ID{"P2"}),
},
},
{
name: "highest peer lowers its height in waitForBlock state, node reaches maxPeerHeight - TS4",
startingHeight: 100,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1 and make requests
sStatusEv("waitForPeer", "waitForBlock", "P1", 101, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
// add P2
sStatusEv("waitForBlock", "waitForBlock", "P2", 200, nil),
// get blocks 100 and 101 from P1
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 100, []int64{}),
sBlockRespEv("waitForBlock", "waitForBlock", "P1", 101, []int64{100}),
// processed block at heights 100
sProcessedBlockEv("waitForBlock", "waitForBlock", nil),
// P2 becomes short
sStatusEv("waitForBlock", "finished", "P2", 100, errPeerLowersItsHeight),
},
},
{
name: "new short peer while in waitForPeer state",
startingHeight: 100,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForPeer", "P1", 3, errPeerTooShort),
},
},
{
name: "new short peer while in waitForBlock state",
startingHeight: 100,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForBlock", "P1", 200, nil),
sStatusEv("waitForBlock", "waitForBlock", "P2", 3, errPeerTooShort),
},
},
{
name: "only peer updated with low height while in waitForBlock state",
startingHeight: 100,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForBlock", "P1", 200, nil),
sStatusEv("waitForBlock", "waitForPeer", "P1", 3, errPeerLowersItsHeight),
},
},
{
name: "peer does not exist in the switch",
startingHeight: 9999999,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
// add P1
sStatusEv("waitForPeer", "waitForBlock", "P1", 20000000, nil),
// send request for block 9999999
// Note: For this block request the "switch missing the peer" error is simulated,
// see implementation of bcReactor interface, sendBlockRequest(), in this file.
sMakeRequestsEvErrored("waitForBlock", "waitForBlock",
maxNumRequests, nil, []p2p.ID{"P1"}),
},
},
}
executeFSMTests(t, tests, true)
}
func TestFSMStopFSM(t *testing.T) {
tests := []testFields{
{
name: "stopFSMEv in unknown",
steps: []fsmStepTestValues{
sStopFSMEv("unknown", "finished"),
},
},
{
name: "stopFSMEv in waitForPeer",
startingHeight: 1,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStopFSMEv("waitForPeer", "finished"),
},
},
{
name: "stopFSMEv in waitForBlock",
startingHeight: 1,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sStopFSMEv("waitForBlock", "finished"),
},
},
}
executeFSMTests(t, tests, false)
}
func TestFSMUnknownElements(t *testing.T) {
tests := []testFields{
{
name: "unknown event for state unknown",
steps: []fsmStepTestValues{
sUnknownFSMEv("unknown"),
},
},
{
name: "unknown event for state waitForPeer",
steps: []fsmStepTestValues{
sStartFSMEv(),
sUnknownFSMEv("waitForPeer"),
},
},
{
name: "unknown event for state waitForBlock",
startingHeight: 1,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sUnknownFSMEv("waitForBlock"),
},
},
}
executeFSMTests(t, tests, false)
}
func TestFSMPeerStateTimeoutEvent(t *testing.T) {
tests := []testFields{
{
name: "timeout event for state waitForPeer while in state waitForPeer - TS1",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStateTimeoutEv("waitForPeer", "finished", "waitForPeer", errNoTallerPeer),
},
},
{
name: "timeout event for state waitForPeer while in a state != waitForPeer",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStateTimeoutEv("waitForPeer", "waitForPeer", "waitForBlock", errTimeoutEventWrongState),
},
},
{
name: "timeout event for state waitForBlock while in state waitForBlock ",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sStateTimeoutEv("waitForBlock", "waitForPeer", "waitForBlock", errNoPeerResponseForCurrentHeights),
},
},
{
name: "timeout event for state waitForBlock while in a state != waitForBlock",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sStateTimeoutEv("waitForBlock", "waitForBlock", "waitForPeer", errTimeoutEventWrongState),
},
},
{
name: "timeout event for state waitForBlock with multiple peers",
startingHeight: 1,
maxRequestsPerPeer: 3,
steps: []fsmStepTestValues{
sStartFSMEv(),
sStatusEv("waitForPeer", "waitForBlock", "P1", 3, nil),
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
sStatusEv("waitForBlock", "waitForBlock", "P2", 3, nil),
sStateTimeoutEv("waitForBlock", "waitForBlock", "waitForBlock", errNoPeerResponseForCurrentHeights),
},
},
}
executeFSMTests(t, tests, false)
}
func makeCorrectTransitionSequence(startingHeight int64, numBlocks int64, numPeers int, randomPeerHeights bool,
maxRequestsPerPeer int, maxPendingRequests int) testFields {
// Generate numPeers peers with random or numBlocks heights according to the randomPeerHeights flag.
peerHeights := make([]int64, numPeers)
for i := 0; i < numPeers; i++ {
if i == 0 {
peerHeights[0] = numBlocks
continue
}
if randomPeerHeights {
peerHeights[i] = int64(tmmath.MaxInt(tmrand.Intn(int(numBlocks)), int(startingHeight)+1))
} else {
peerHeights[i] = numBlocks
}
}
// Approximate the slice capacity to save time for appends.
testSteps := make([]fsmStepTestValues, 0, 3*numBlocks+int64(numPeers))
testName := fmt.Sprintf("%v-blocks %v-startingHeight %v-peers %v-maxRequestsPerPeer %v-maxNumRequests",
numBlocks, startingHeight, numPeers, maxRequestsPerPeer, maxPendingRequests)
// Add startFSMEv step.
testSteps = append(testSteps, sStartFSMEv())
// For each peer, add statusResponseEv step.
for i := 0; i < numPeers; i++ {
peerName := fmt.Sprintf("P%d", i)
if i == 0 {
testSteps = append(
testSteps,
sStatusEv("waitForPeer", "waitForBlock", p2p.ID(peerName), peerHeights[i], nil))
} else {
testSteps = append(testSteps,
sStatusEv("waitForBlock", "waitForBlock", p2p.ID(peerName), peerHeights[i], nil))
}
}
height := startingHeight
numBlocksReceived := 0
prevBlocks := make([]int64, 0, maxPendingRequests)
forLoop:
for i := 0; i < int(numBlocks); i++ {
// Add the makeRequestEv step periodically.
if i%maxRequestsPerPeer == 0 {
testSteps = append(
testSteps,
sMakeRequestsEv("waitForBlock", "waitForBlock", maxNumRequests),
)
}
// Add the blockRespEv step
testSteps = append(
testSteps,
sBlockRespEv("waitForBlock", "waitForBlock",
"P0", height, prevBlocks))
prevBlocks = append(prevBlocks, height)
height++
numBlocksReceived++
// Add the processedBlockEv step periodically.
if numBlocksReceived >= maxRequestsPerPeer || height >= numBlocks {
for j := int(height) - numBlocksReceived; j < int(height); j++ {
if j >= int(numBlocks) {
// This is the last block that is processed, we should be in "finished" state.
testSteps = append(
testSteps,
sProcessedBlockEv("waitForBlock", "finished", nil))
break forLoop
}
testSteps = append(
testSteps,
sProcessedBlockEv("waitForBlock", "waitForBlock", nil))
}
numBlocksReceived = 0
prevBlocks = make([]int64, 0, maxPendingRequests)
}
}
return testFields{
name: testName,
startingHeight: startingHeight,
maxRequestsPerPeer: maxRequestsPerPeer,
maxPendingRequests: maxPendingRequests,
steps: testSteps,
}
}
const (
maxStartingHeightTest = 100
maxRequestsPerPeerTest = 20
maxTotalPendingRequestsTest = 600
maxNumPeersTest = 1000
maxNumBlocksInChainTest = 10000 // should be smaller than 9999999
)
func makeCorrectTransitionSequenceWithRandomParameters() testFields {
// Generate a starting height for fast sync.
startingHeight := int64(tmrand.Intn(maxStartingHeightTest) + 1)
// Generate the number of requests per peer.
maxRequestsPerPeer := tmrand.Intn(maxRequestsPerPeerTest) + 1
// Generate the maximum number of total pending requests, >= maxRequestsPerPeer.
maxPendingRequests := tmrand.Intn(maxTotalPendingRequestsTest-maxRequestsPerPeer) + maxRequestsPerPeer
// Generate the number of blocks to be synced.
numBlocks := int64(tmrand.Intn(maxNumBlocksInChainTest)) + startingHeight
// Generate a number of peers.
numPeers := tmrand.Intn(maxNumPeersTest) + 1
return makeCorrectTransitionSequence(startingHeight, numBlocks, numPeers, true, maxRequestsPerPeer, maxPendingRequests)
}
func shouldApplyProcessedBlockEvStep(step *fsmStepTestValues, testBcR *testReactor) bool {
if step.event == processedBlockEv {
_, err := testBcR.fsm.pool.BlockAndPeerAtHeight(testBcR.fsm.pool.Height)
if err == errMissingBlock {
return false
}
_, err = testBcR.fsm.pool.BlockAndPeerAtHeight(testBcR.fsm.pool.Height + 1)
if err == errMissingBlock {
return false
}
}
return true
}
func TestFSMCorrectTransitionSequences(t *testing.T) {
tests := []testFields{
makeCorrectTransitionSequence(1, 100, 10, true, 10, 40),
makeCorrectTransitionSequenceWithRandomParameters(),
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
// Create test reactor
testBcR := newTestReactor(tt.startingHeight)
if tt.maxRequestsPerPeer != 0 {
maxRequestsPerPeer = tt.maxRequestsPerPeer
}
for _, step := range tt.steps {
step := step
assert.Equal(t, step.currentState, testBcR.fsm.state.name)
oldNumStatusRequests := testBcR.numStatusRequests
fixBlockResponseEvStep(&step, testBcR)
if !shouldApplyProcessedBlockEvStep(&step, testBcR) {
continue
}
fsmErr := sendEventToFSM(testBcR.fsm, step.event, step.data)
assert.Equal(t, step.wantErr, fsmErr)
if step.wantStatusReqSent {
assert.Equal(t, oldNumStatusRequests+1, testBcR.numStatusRequests)
} else {
assert.Equal(t, oldNumStatusRequests, testBcR.numStatusRequests)
}
assert.Equal(t, step.wantState, testBcR.fsm.state.name)
if step.wantState == "finished" {
assert.True(t, testBcR.fsm.isCaughtUp())
}
}
})
}
}
// ----------------------------------------
// implements the bcRNotifier
func (testR *testReactor) sendPeerError(err error, peerID p2p.ID) {
testR.logger.Info("Reactor received sendPeerError call from FSM", "peer", peerID, "err", err)
testR.lastPeerError.peerID = peerID
testR.lastPeerError.err = err
}
func (testR *testReactor) sendStatusRequest() {
testR.logger.Info("Reactor received sendStatusRequest call from FSM")
testR.numStatusRequests++
}
func (testR *testReactor) sendBlockRequest(peerID p2p.ID, height int64) error {
testR.logger.Info("Reactor received sendBlockRequest call from FSM", "peer", peerID, "height", height)
testR.numBlockRequests++
testR.lastBlockRequest.peerID = peerID
testR.lastBlockRequest.height = height
if height == 9999999 {
// simulate switch does not have peer
return errNilPeerForBlockRequest
}
return nil
}
func (testR *testReactor) resetStateTimer(name string, timer **time.Timer, timeout time.Duration) {
testR.logger.Info("Reactor received resetStateTimer call from FSM", "state", name, "timeout", timeout)
if _, ok := testR.stateTimerStarts[name]; !ok {
testR.stateTimerStarts[name] = 1
} else {
testR.stateTimerStarts[name]++
}
}
func (testR *testReactor) switchToConsensus() {
}
// ----------------------------------------

View File

@@ -1,365 +0,0 @@
package v1
import (
"fmt"
"os"
"sort"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tm-db"
abci "github.com/tendermint/tendermint/abci/types"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/libs/log"
mpmocks "github.com/tendermint/tendermint/mempool/mocks"
"github.com/tendermint/tendermint/p2p"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
)
var config *cfg.Config
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []types.PrivValidator) {
validators := make([]types.GenesisValidator, numValidators)
privValidators := make([]types.PrivValidator, numValidators)
for i := 0; i < numValidators; i++ {
val, privVal := types.RandValidator(randPower, minPower)
validators[i] = types.GenesisValidator{
PubKey: val.PubKey,
Power: val.VotingPower,
}
privValidators[i] = privVal
}
sort.Sort(types.PrivValidatorsByAddress(privValidators))
return &types.GenesisDoc{
GenesisTime: tmtime.Now(),
ChainID: config.ChainID(),
Validators: validators,
}, privValidators
}
func makeVote(
t *testing.T,
header *types.Header,
blockID types.BlockID,
valset *types.ValidatorSet,
privVal types.PrivValidator) *types.Vote {
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)
valIdx, _ := valset.GetByAddress(pubKey.Address())
vote := &types.Vote{
ValidatorAddress: pubKey.Address(),
ValidatorIndex: valIdx,
Height: header.Height,
Round: 1,
Timestamp: tmtime.Now(),
Type: tmproto.PrecommitType,
BlockID: blockID,
}
vpb := vote.ToProto()
_ = privVal.SignVote(header.ChainID, vpb)
vote.Signature = vpb.Signature
return vote
}
type BlockchainReactorPair struct {
bcR *BlockchainReactor
conR *consensusReactorTest
}
func newBlockchainReactor(
t *testing.T,
logger log.Logger,
genDoc *types.GenesisDoc,
privVals []types.PrivValidator,
maxBlockHeight int64) *BlockchainReactor {
if len(privVals) != 1 {
panic("only support one validator")
}
app := &testApp{}
cc := proxy.NewLocalClientCreator(app)
proxyApp := proxy.NewAppConns(cc)
err := proxyApp.Start()
if err != nil {
panic(fmt.Errorf("error start app: %w", err))
}
blockDB := dbm.NewMemDB()
stateDB := dbm.NewMemDB()
stateStore := sm.NewStore(stateDB)
blockStore := store.NewBlockStore(blockDB)
state, err := stateStore.LoadFromDBOrGenesisDoc(genDoc)
if err != nil {
panic(fmt.Errorf("error constructing state from genesis file: %w", err))
}
mp := &mpmocks.Mempool{}
mp.On("Lock").Return()
mp.On("Unlock").Return()
mp.On("FlushAppConn", mock.Anything).Return(nil)
mp.On("Update",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything).Return(nil)
// Make the BlockchainReactor itself.
// NOTE we have to create and commit the blocks first because
// pool.height is determined from the store.
fastSync := true
db := dbm.NewMemDB()
stateStore = sm.NewStore(db)
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
mp, sm.EmptyEvidencePool{})
if err = stateStore.Save(state); err != nil {
panic(err)
}
// let's add some blocks in
for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ {
lastCommit := types.NewCommit(blockHeight-1, 1, types.BlockID{}, nil)
if blockHeight > 1 {
lastBlockMeta := blockStore.LoadBlockMeta(blockHeight - 1)
lastBlock := blockStore.LoadBlock(blockHeight - 1)
vote := makeVote(t, &lastBlock.Header, lastBlockMeta.BlockID, state.Validators, privVals[0])
lastCommit = types.NewCommit(vote.Height, vote.Round, lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()})
}
thisBlock := sf.MakeBlock(state, blockHeight, lastCommit)
thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes)
require.NoError(t, err)
blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()}
state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock)
if err != nil {
panic(fmt.Errorf("error apply block: %w", err))
}
blockStore.SaveBlock(thisBlock, thisParts, lastCommit)
}
bcReactor := NewBlockchainReactor(state.Copy(), blockExec, blockStore, fastSync)
bcReactor.SetLogger(logger.With("module", "blockchain"))
return bcReactor
}
func newBlockchainReactorPair(
t *testing.T,
logger log.Logger,
genDoc *types.GenesisDoc,
privVals []types.PrivValidator,
maxBlockHeight int64) BlockchainReactorPair {
consensusReactor := &consensusReactorTest{}
consensusReactor.BaseReactor = *p2p.NewBaseReactor("Consensus reactor", consensusReactor)
return BlockchainReactorPair{
newBlockchainReactor(t, logger, genDoc, privVals, maxBlockHeight),
consensusReactor}
}
type consensusReactorTest struct {
p2p.BaseReactor // BaseService + p2p.Switch
switchedToConsensus bool
mtx sync.Mutex
}
func (conR *consensusReactorTest) SwitchToConsensus(state sm.State, blocksSynced bool) {
conR.mtx.Lock()
defer conR.mtx.Unlock()
conR.switchedToConsensus = true
}
func TestFastSyncNoBlockResponse(t *testing.T) {
config = cfg.ResetTestRoot("blockchain_new_reactor_test")
defer os.RemoveAll(config.RootDir)
genDoc, privVals := randGenesisDoc(1, false, 30)
maxBlockHeight := int64(65)
reactorPairs := make([]BlockchainReactorPair, 2)
logger := log.TestingLogger()
reactorPairs[0] = newBlockchainReactorPair(t, logger, genDoc, privVals, maxBlockHeight)
reactorPairs[1] = newBlockchainReactorPair(t, logger, genDoc, privVals, 0)
p2p.MakeConnectedSwitches(config.P2P, 2, func(i int, s *p2p.Switch) *p2p.Switch {
s.AddReactor("BLOCKCHAIN", reactorPairs[i].bcR)
s.AddReactor("CONSENSUS", reactorPairs[i].conR)
moduleName := fmt.Sprintf("blockchain-%v", i)
reactorPairs[i].bcR.SetLogger(logger.With("module", moduleName))
return s
}, p2p.Connect2Switches)
defer func() {
for _, r := range reactorPairs {
_ = r.bcR.Stop()
_ = r.conR.Stop()
}
}()
tests := []struct {
height int64
existent bool
}{
{maxBlockHeight + 2, false},
{10, true},
{1, true},
{maxBlockHeight + 100, false},
}
for {
time.Sleep(10 * time.Millisecond)
reactorPairs[1].conR.mtx.Lock()
if reactorPairs[1].conR.switchedToConsensus {
reactorPairs[1].conR.mtx.Unlock()
break
}
reactorPairs[1].conR.mtx.Unlock()
}
assert.Equal(t, maxBlockHeight, reactorPairs[0].bcR.store.Height())
for _, tt := range tests {
block := reactorPairs[1].bcR.store.LoadBlock(tt.height)
if tt.existent {
assert.True(t, block != nil)
} else {
assert.True(t, block == nil)
}
}
}
// NOTE: This is too hard to test without
// an easy way to add test peer to switch
// or without significant refactoring of the module.
// Alternatively we could actually dial a TCP conn but
// that seems extreme.
func TestFastSyncBadBlockStopsPeer(t *testing.T) {
numNodes := 4
maxBlockHeight := int64(148)
config = cfg.ResetTestRoot("blockchain_reactor_test")
defer os.RemoveAll(config.RootDir)
genDoc, privVals := randGenesisDoc(1, false, 30)
otherChain := newBlockchainReactorPair(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight)
defer func() {
_ = otherChain.bcR.Stop()
_ = otherChain.conR.Stop()
}()
reactorPairs := make([]BlockchainReactorPair, numNodes)
logger := make([]log.Logger, numNodes)
for i := 0; i < numNodes; i++ {
logger[i] = log.TestingLogger()
height := int64(0)
if i == 0 {
height = maxBlockHeight
}
reactorPairs[i] = newBlockchainReactorPair(t, logger[i], genDoc, privVals, height)
}
switches := p2p.MakeConnectedSwitches(config.P2P, numNodes, func(i int, s *p2p.Switch) *p2p.Switch {
reactorPairs[i].conR.mtx.Lock()
s.AddReactor("BLOCKCHAIN", reactorPairs[i].bcR)
s.AddReactor("CONSENSUS", reactorPairs[i].conR)
moduleName := fmt.Sprintf("blockchain-%v", i)
reactorPairs[i].bcR.SetLogger(logger[i].With("module", moduleName))
reactorPairs[i].conR.mtx.Unlock()
return s
}, p2p.Connect2Switches)
defer func() {
for _, r := range reactorPairs {
_ = r.bcR.Stop()
_ = r.conR.Stop()
}
}()
outerFor:
for {
time.Sleep(10 * time.Millisecond)
for i := 0; i < numNodes; i++ {
reactorPairs[i].conR.mtx.Lock()
if !reactorPairs[i].conR.switchedToConsensus {
reactorPairs[i].conR.mtx.Unlock()
continue outerFor
}
reactorPairs[i].conR.mtx.Unlock()
}
break
}
// at this time, reactors[0-3] is the newest
assert.Equal(t, numNodes-1, reactorPairs[1].bcR.Switch.Peers().Size())
// mark last reactorPair as an invalid peer
reactorPairs[numNodes-1].bcR.store = otherChain.bcR.store
lastLogger := log.TestingLogger()
lastReactorPair := newBlockchainReactorPair(t, lastLogger, genDoc, privVals, 0)
reactorPairs = append(reactorPairs, lastReactorPair)
switches = append(switches, p2p.MakeConnectedSwitches(config.P2P, 1, func(i int, s *p2p.Switch) *p2p.Switch {
s.AddReactor("BLOCKCHAIN", reactorPairs[len(reactorPairs)-1].bcR)
s.AddReactor("CONSENSUS", reactorPairs[len(reactorPairs)-1].conR)
moduleName := fmt.Sprintf("blockchain-%v", len(reactorPairs)-1)
reactorPairs[len(reactorPairs)-1].bcR.SetLogger(lastLogger.With("module", moduleName))
return s
}, p2p.Connect2Switches)...)
for i := 0; i < len(reactorPairs)-1; i++ {
p2p.Connect2Switches(switches, i, len(reactorPairs)-1)
}
for {
time.Sleep(1 * time.Second)
lastReactorPair.conR.mtx.Lock()
if lastReactorPair.conR.switchedToConsensus {
lastReactorPair.conR.mtx.Unlock()
break
}
lastReactorPair.conR.mtx.Unlock()
if lastReactorPair.bcR.Switch.Peers().Size() == 0 {
break
}
}
assert.True(t, lastReactorPair.bcR.Switch.Peers().Size() < len(reactorPairs)-1)
}
type testApp struct {
abci.BaseApplication
}

View File

@@ -1,140 +0,0 @@
package v2
import (
"fmt"
bc "github.com/tendermint/tendermint/blockchain"
"github.com/tendermint/tendermint/p2p"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain"
"github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
type iIO interface {
sendBlockRequest(peerID p2p.ID, height int64) error
sendBlockToPeer(block *types.Block, peerID p2p.ID) error
sendBlockNotFound(height int64, peerID p2p.ID) error
sendStatusResponse(base, height int64, peerID p2p.ID) error
broadcastStatusRequest() error
trySwitchToConsensus(state state.State, skipWAL bool) bool
}
type switchIO struct {
sw *p2p.Switch
}
func newSwitchIo(sw *p2p.Switch) *switchIO {
return &switchIO{
sw: sw,
}
}
const (
// BlockchainChannel is a channel for blocks and status updates (`BlockStore` height)
BlockchainChannel = byte(0x40)
)
type consensusReactor interface {
// for when we switch from blockchain reactor and fast sync to
// the consensus machine
SwitchToConsensus(state state.State, skipWAL bool)
}
func (sio *switchIO) sendBlockRequest(peerID p2p.ID, height int64) error {
peer := sio.sw.Peers().Get(peerID)
if peer == nil {
return fmt.Errorf("peer not found")
}
msgBytes, err := bc.EncodeMsg(&bcproto.BlockRequest{Height: height})
if err != nil {
return err
}
queued := peer.TrySend(BlockchainChannel, msgBytes)
if !queued {
return fmt.Errorf("send queue full")
}
return nil
}
func (sio *switchIO) sendStatusResponse(base int64, height int64, peerID p2p.ID) error {
peer := sio.sw.Peers().Get(peerID)
if peer == nil {
return fmt.Errorf("peer not found")
}
msgBytes, err := bc.EncodeMsg(&bcproto.StatusResponse{Height: height, Base: base})
if err != nil {
return err
}
if queued := peer.TrySend(BlockchainChannel, msgBytes); !queued {
return fmt.Errorf("peer queue full")
}
return nil
}
func (sio *switchIO) sendBlockToPeer(block *types.Block, peerID p2p.ID) error {
peer := sio.sw.Peers().Get(peerID)
if peer == nil {
return fmt.Errorf("peer not found")
}
if block == nil {
panic("trying to send nil block")
}
bpb, err := block.ToProto()
if err != nil {
return err
}
msgBytes, err := bc.EncodeMsg(&bcproto.BlockResponse{Block: bpb})
if err != nil {
return err
}
if queued := peer.TrySend(BlockchainChannel, msgBytes); !queued {
return fmt.Errorf("peer queue full")
}
return nil
}
func (sio *switchIO) sendBlockNotFound(height int64, peerID p2p.ID) error {
peer := sio.sw.Peers().Get(peerID)
if peer == nil {
return fmt.Errorf("peer not found")
}
msgBytes, err := bc.EncodeMsg(&bcproto.NoBlockResponse{Height: height})
if err != nil {
return err
}
if queued := peer.TrySend(BlockchainChannel, msgBytes); !queued {
return fmt.Errorf("peer queue full")
}
return nil
}
func (sio *switchIO) trySwitchToConsensus(state state.State, skipWAL bool) bool {
conR, ok := sio.sw.Reactor("CONSENSUS").(consensusReactor)
if ok {
conR.SwitchToConsensus(state, skipWAL)
}
return ok
}
func (sio *switchIO) broadcastStatusRequest() error {
msgBytes, err := bc.EncodeMsg(&bcproto.StatusRequest{})
if err != nil {
return err
}
// XXX: maybe we should use an io specific peer list here
sio.sw.Broadcast(BlockchainChannel, msgBytes)
return nil
}

View File

@@ -1,125 +0,0 @@
package v2
import (
"github.com/go-kit/kit/metrics"
"github.com/go-kit/kit/metrics/discard"
"github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
)
const (
// MetricsSubsystem is a subsystem shared by all metrics exposed by this
// package.
MetricsSubsystem = "blockchain"
)
// Metrics contains metrics exposed by this package.
type Metrics struct {
// events_in
EventsIn metrics.Counter
// events_in
EventsHandled metrics.Counter
// events_out
EventsOut metrics.Counter
// errors_in
ErrorsIn metrics.Counter
// errors_handled
ErrorsHandled metrics.Counter
// errors_out
ErrorsOut metrics.Counter
// events_shed
EventsShed metrics.Counter
// events_sent
EventsSent metrics.Counter
// errors_sent
ErrorsSent metrics.Counter
// errors_shed
ErrorsShed metrics.Counter
}
// PrometheusMetrics returns metrics for in and out events, errors, etc. handled by routines.
// Can we burn in the routine name here?
func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
labels := []string{}
for i := 0; i < len(labelsAndValues); i += 2 {
labels = append(labels, labelsAndValues[i])
}
return &Metrics{
EventsIn: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "events_in",
Help: "Events read from the channel.",
}, labels).With(labelsAndValues...),
EventsHandled: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "events_handled",
Help: "Events handled",
}, labels).With(labelsAndValues...),
EventsOut: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "events_out",
Help: "Events output from routine.",
}, labels).With(labelsAndValues...),
ErrorsIn: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "errors_in",
Help: "Errors read from the channel.",
}, labels).With(labelsAndValues...),
ErrorsHandled: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "errors_handled",
Help: "Errors handled.",
}, labels).With(labelsAndValues...),
ErrorsOut: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "errors_out",
Help: "Errors output from routine.",
}, labels).With(labelsAndValues...),
ErrorsSent: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "errors_sent",
Help: "Errors sent to routine.",
}, labels).With(labelsAndValues...),
ErrorsShed: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "errors_shed",
Help: "Errors dropped from sending.",
}, labels).With(labelsAndValues...),
EventsSent: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "events_sent",
Help: "Events sent to routine.",
}, labels).With(labelsAndValues...),
EventsShed: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "events_shed",
Help: "Events dropped from sending.",
}, labels).With(labelsAndValues...),
}
}
// NopMetrics returns no-op Metrics.
func NopMetrics() *Metrics {
return &Metrics{
EventsIn: discard.NewCounter(),
EventsHandled: discard.NewCounter(),
EventsOut: discard.NewCounter(),
ErrorsIn: discard.NewCounter(),
ErrorsHandled: discard.NewCounter(),
ErrorsOut: discard.NewCounter(),
EventsShed: discard.NewCounter(),
EventsSent: discard.NewCounter(),
ErrorsSent: discard.NewCounter(),
ErrorsShed: discard.NewCounter(),
}
}

View File

@@ -1,193 +0,0 @@
package v2
import (
"fmt"
"github.com/tendermint/tendermint/p2p"
tmState "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
// Events generated by the processor:
// block execution failure, event will indicate the peer(s) that caused the error
type pcBlockVerificationFailure struct {
priorityNormal
height int64
firstPeerID p2p.ID
secondPeerID p2p.ID
}
func (e pcBlockVerificationFailure) String() string {
return fmt.Sprintf("pcBlockVerificationFailure{%d 1st peer: %v, 2nd peer: %v}",
e.height, e.firstPeerID, e.secondPeerID)
}
// successful block execution
type pcBlockProcessed struct {
priorityNormal
height int64
peerID p2p.ID
}
func (e pcBlockProcessed) String() string {
return fmt.Sprintf("pcBlockProcessed{%d peer: %v}", e.height, e.peerID)
}
// processor has finished
type pcFinished struct {
priorityNormal
blocksSynced int
tmState tmState.State
}
func (p pcFinished) Error() string {
return "finished"
}
type queueItem struct {
block *types.Block
peerID p2p.ID
}
type blockQueue map[int64]queueItem
type pcState struct {
// blocks waiting to be processed
queue blockQueue
// draining indicates that the next rProcessBlock event with a queue miss constitutes completion
draining bool
// the number of blocks successfully synced by the processor
blocksSynced int
// the processorContext which contains the processor dependencies
context processorContext
}
func (state *pcState) String() string {
return fmt.Sprintf("height: %d queue length: %d draining: %v blocks synced: %d",
state.height(), len(state.queue), state.draining, state.blocksSynced)
}
// newPcState returns a pcState initialized with the last verified block enqueued
func newPcState(context processorContext) *pcState {
return &pcState{
queue: blockQueue{},
draining: false,
blocksSynced: 0,
context: context,
}
}
// nextTwo returns the next two unverified blocks
func (state *pcState) nextTwo() (queueItem, queueItem, error) {
if first, ok := state.queue[state.height()+1]; ok {
if second, ok := state.queue[state.height()+2]; ok {
return first, second, nil
}
}
return queueItem{}, queueItem{}, fmt.Errorf("not found")
}
// synced returns true when at most the last verified block remains in the queue
func (state *pcState) synced() bool {
return len(state.queue) <= 1
}
func (state *pcState) enqueue(peerID p2p.ID, block *types.Block, height int64) {
if item, ok := state.queue[height]; ok {
panic(fmt.Sprintf(
"duplicate block %d (%X) enqueued by processor (sent by %v; existing block %X from %v)",
height, block.Hash(), peerID, item.block.Hash(), item.peerID))
}
state.queue[height] = queueItem{block: block, peerID: peerID}
}
func (state *pcState) height() int64 {
return state.context.tmState().LastBlockHeight
}
// purgePeer moves all unprocessed blocks from the queue
func (state *pcState) purgePeer(peerID p2p.ID) {
// what if height is less than state.height?
for height, item := range state.queue {
if item.peerID == peerID {
delete(state.queue, height)
}
}
}
// handle processes FSM events
func (state *pcState) handle(event Event) (Event, error) {
switch event := event.(type) {
case bcResetState:
state.context.setState(event.state)
return noOp, nil
case scFinishedEv:
if state.synced() {
return pcFinished{tmState: state.context.tmState(), blocksSynced: state.blocksSynced}, nil
}
state.draining = true
return noOp, nil
case scPeerError:
state.purgePeer(event.peerID)
return noOp, nil
case scBlockReceived:
if event.block == nil {
return noOp, nil
}
// enqueue block if height is higher than state height, else ignore it
if event.block.Height > state.height() {
state.enqueue(event.peerID, event.block, event.block.Height)
}
return noOp, nil
case rProcessBlock:
tmState := state.context.tmState()
firstItem, secondItem, err := state.nextTwo()
if err != nil {
if state.draining {
return pcFinished{tmState: tmState, blocksSynced: state.blocksSynced}, nil
}
return noOp, nil
}
first, second := firstItem.block, secondItem.block
firstParts, err := first.MakePartSet(types.BlockPartSizeBytes)
if err != nil {
panic(fmt.Sprintf("failed to make part set, height %d: %v ", first.Height, err.Error()))
}
firstID := types.BlockID{Hash: first.Hash(), PartSetHeader: firstParts.Header()}
// verify if +second+ last commit "confirms" +first+ block
err = state.context.verifyCommit(tmState.ChainID, firstID, first.Height, second.LastCommit)
if err != nil {
state.purgePeer(firstItem.peerID)
if firstItem.peerID != secondItem.peerID {
state.purgePeer(secondItem.peerID)
}
return pcBlockVerificationFailure{
height: first.Height, firstPeerID: firstItem.peerID, secondPeerID: secondItem.peerID},
nil
}
state.context.saveBlock(first, firstParts, second.LastCommit)
if err := state.context.applyBlock(firstID, first); err != nil {
panic(fmt.Sprintf("failed to process committed block (%d:%X): %v", first.Height, first.Hash(), err))
}
delete(state.queue, first.Height)
state.blocksSynced++
return pcBlockProcessed{height: first.Height, peerID: firstItem.peerID}, nil
}
return noOp, nil
}

View File

@@ -1,100 +0,0 @@
package v2
import (
"fmt"
"github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
type processorContext interface {
applyBlock(blockID types.BlockID, block *types.Block) error
verifyCommit(chainID string, blockID types.BlockID, height int64, commit *types.Commit) error
saveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit)
tmState() state.State
setState(state.State)
}
type pContext struct {
store blockStore
applier blockApplier
state state.State
}
func newProcessorContext(st blockStore, ex blockApplier, s state.State) *pContext {
return &pContext{
store: st,
applier: ex,
state: s,
}
}
func (pc *pContext) applyBlock(blockID types.BlockID, block *types.Block) error {
newState, _, err := pc.applier.ApplyBlock(pc.state, blockID, block)
pc.state = newState
return err
}
func (pc pContext) tmState() state.State {
return pc.state
}
func (pc *pContext) setState(state state.State) {
pc.state = state
}
func (pc pContext) verifyCommit(chainID string, blockID types.BlockID, height int64, commit *types.Commit) error {
return pc.state.Validators.VerifyCommitLight(chainID, blockID, height, commit)
}
func (pc *pContext) saveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
pc.store.SaveBlock(block, blockParts, seenCommit)
}
type mockPContext struct {
applicationBL []int64
verificationBL []int64
state state.State
}
func newMockProcessorContext(
state state.State,
verificationBlackList []int64,
applicationBlackList []int64) *mockPContext {
return &mockPContext{
applicationBL: applicationBlackList,
verificationBL: verificationBlackList,
state: state,
}
}
func (mpc *mockPContext) applyBlock(blockID types.BlockID, block *types.Block) error {
for _, h := range mpc.applicationBL {
if h == block.Height {
return fmt.Errorf("generic application error")
}
}
mpc.state.LastBlockHeight = block.Height
return nil
}
func (mpc *mockPContext) verifyCommit(chainID string, blockID types.BlockID, height int64, commit *types.Commit) error {
for _, h := range mpc.verificationBL {
if h == height {
return fmt.Errorf("generic verification error")
}
}
return nil
}
func (mpc *mockPContext) saveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
}
func (mpc *mockPContext) setState(state state.State) {
mpc.state = state
}
func (mpc *mockPContext) tmState() state.State {
return mpc.state
}

View File

@@ -1,306 +0,0 @@
package v2
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tendermint/tendermint/p2p"
tmState "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
// pcBlock is a test helper structure with simple types. Its purpose is to help with test readability.
type pcBlock struct {
pid string
height int64
}
// params is a test structure used to create processor state.
type params struct {
height int64
items []pcBlock
blocksSynced int
verBL []int64
appBL []int64
draining bool
}
// makePcBlock makes an empty block.
func makePcBlock(height int64) *types.Block {
return &types.Block{Header: types.Header{Height: height}}
}
// makeState takes test parameters and creates a specific processor state.
func makeState(p *params) *pcState {
var (
tmState = tmState.State{LastBlockHeight: p.height}
context = newMockProcessorContext(tmState, p.verBL, p.appBL)
)
state := newPcState(context)
for _, item := range p.items {
state.enqueue(p2p.ID(item.pid), makePcBlock(item.height), item.height)
}
state.blocksSynced = p.blocksSynced
state.draining = p.draining
return state
}
func mBlockResponse(peerID p2p.ID, height int64) scBlockReceived {
return scBlockReceived{
peerID: peerID,
block: makePcBlock(height),
}
}
type pcFsmMakeStateValues struct {
currentState *params
event Event
wantState *params
wantNextEvent Event
wantErr error
wantPanic bool
}
type testFields struct {
name string
steps []pcFsmMakeStateValues
}
func executeProcessorTests(t *testing.T, tests []testFields) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
var state *pcState
for _, step := range tt.steps {
defer func() {
r := recover()
if (r != nil) != step.wantPanic {
t.Errorf("recover = %v, wantPanic = %v", r, step.wantPanic)
}
}()
// First step must always initialize the currentState as state.
if step.currentState != nil {
state = makeState(step.currentState)
}
if state == nil {
panic("Bad (initial?) step")
}
nextEvent, err := state.handle(step.event)
t.Log(state)
assert.Equal(t, step.wantErr, err)
assert.Equal(t, makeState(step.wantState), state)
assert.Equal(t, step.wantNextEvent, nextEvent)
// Next step may use the wantedState as their currentState.
state = makeState(step.wantState)
}
})
}
}
func TestRProcessPeerError(t *testing.T) {
tests := []testFields{
{
name: "error for existing peer",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}},
event: scPeerError{peerID: "P2"},
wantState: &params{items: []pcBlock{{"P1", 1}}},
wantNextEvent: noOp,
},
},
},
{
name: "error for unknown peer",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}},
event: scPeerError{peerID: "P3"},
wantState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}},
wantNextEvent: noOp,
},
},
},
}
executeProcessorTests(t, tests)
}
func TestPcBlockResponse(t *testing.T) {
tests := []testFields{
{
name: "add one block",
steps: []pcFsmMakeStateValues{
{
currentState: &params{}, event: mBlockResponse("P1", 1),
wantState: &params{items: []pcBlock{{"P1", 1}}}, wantNextEvent: noOp,
},
},
},
{
name: "add two blocks",
steps: []pcFsmMakeStateValues{
{
currentState: &params{}, event: mBlockResponse("P1", 3),
wantState: &params{items: []pcBlock{{"P1", 3}}}, wantNextEvent: noOp,
},
{ // use previous wantState as currentState,
event: mBlockResponse("P1", 4),
wantState: &params{items: []pcBlock{{"P1", 3}, {"P1", 4}}}, wantNextEvent: noOp,
},
},
},
}
executeProcessorTests(t, tests)
}
func TestRProcessBlockSuccess(t *testing.T) {
tests := []testFields{
{
name: "noop - no blocks over current height",
steps: []pcFsmMakeStateValues{
{
currentState: &params{}, event: rProcessBlock{},
wantState: &params{}, wantNextEvent: noOp,
},
},
},
{
name: "noop - high new blocks",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 5, items: []pcBlock{{"P1", 30}, {"P2", 31}}}, event: rProcessBlock{},
wantState: &params{height: 5, items: []pcBlock{{"P1", 30}, {"P2", 31}}}, wantNextEvent: noOp,
},
},
},
{
name: "blocks H+1 and H+2 present",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}}, event: rProcessBlock{},
wantState: &params{height: 1, items: []pcBlock{{"P2", 2}}, blocksSynced: 1},
wantNextEvent: pcBlockProcessed{height: 1, peerID: "P1"},
},
},
},
{
name: "blocks H+1 and H+2 present after draining",
steps: []pcFsmMakeStateValues{
{ // some contiguous blocks - on stop check draining is set
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}, {"P1", 4}}},
event: scFinishedEv{},
wantState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}, {"P1", 4}}, draining: true},
wantNextEvent: noOp,
},
{
event: rProcessBlock{},
wantState: &params{height: 1, items: []pcBlock{{"P2", 2}, {"P1", 4}}, blocksSynced: 1, draining: true},
wantNextEvent: pcBlockProcessed{height: 1, peerID: "P1"},
},
{ // finish when H+1 or/and H+2 are missing
event: rProcessBlock{},
wantState: &params{height: 1, items: []pcBlock{{"P2", 2}, {"P1", 4}}, blocksSynced: 1, draining: true},
wantNextEvent: pcFinished{tmState: tmState.State{LastBlockHeight: 1}, blocksSynced: 1},
},
},
},
}
executeProcessorTests(t, tests)
}
func TestRProcessBlockFailures(t *testing.T) {
tests := []testFields{
{
name: "blocks H+1 and H+2 present from different peers - H+1 verification fails ",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}, verBL: []int64{1}}, event: rProcessBlock{},
wantState: &params{items: []pcBlock{}, verBL: []int64{1}},
wantNextEvent: pcBlockVerificationFailure{height: 1, firstPeerID: "P1", secondPeerID: "P2"},
},
},
},
{
name: "blocks H+1 and H+2 present from same peer - H+1 applyBlock fails ",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}}, appBL: []int64{1}}, event: rProcessBlock{},
wantState: &params{items: []pcBlock{}, appBL: []int64{1}}, wantPanic: true,
},
},
},
{
name: "blocks H+1 and H+2 present from same peers - H+1 verification fails ",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 0, items: []pcBlock{{"P1", 1}, {"P1", 2}, {"P2", 3}},
verBL: []int64{1}}, event: rProcessBlock{},
wantState: &params{height: 0, items: []pcBlock{{"P2", 3}}, verBL: []int64{1}},
wantNextEvent: pcBlockVerificationFailure{height: 1, firstPeerID: "P1", secondPeerID: "P1"},
},
},
},
{
name: "blocks H+1 and H+2 present from different peers - H+1 applyBlock fails ",
steps: []pcFsmMakeStateValues{
{
currentState: &params{items: []pcBlock{{"P1", 1}, {"P2", 2}, {"P2", 3}}, appBL: []int64{1}},
event: rProcessBlock{},
wantState: &params{items: []pcBlock{{"P2", 3}}, appBL: []int64{1}}, wantPanic: true,
},
},
},
}
executeProcessorTests(t, tests)
}
func TestScFinishedEv(t *testing.T) {
tests := []testFields{
{
name: "no blocks",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 100, items: []pcBlock{}, blocksSynced: 100}, event: scFinishedEv{},
wantState: &params{height: 100, items: []pcBlock{}, blocksSynced: 100},
wantNextEvent: pcFinished{tmState: tmState.State{LastBlockHeight: 100}, blocksSynced: 100},
},
},
},
{
name: "maxHeight+1 block present",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 100, items: []pcBlock{
{"P1", 101}}, blocksSynced: 100}, event: scFinishedEv{},
wantState: &params{height: 100, items: []pcBlock{{"P1", 101}}, blocksSynced: 100},
wantNextEvent: pcFinished{tmState: tmState.State{LastBlockHeight: 100}, blocksSynced: 100},
},
},
},
{
name: "more blocks present",
steps: []pcFsmMakeStateValues{
{
currentState: &params{height: 100, items: []pcBlock{
{"P1", 101}, {"P1", 102}}, blocksSynced: 100}, event: scFinishedEv{},
wantState: &params{height: 100, items: []pcBlock{
{"P1", 101}, {"P1", 102}}, blocksSynced: 100, draining: true},
wantNextEvent: noOp,
wantErr: nil,
},
},
},
}
executeProcessorTests(t, tests)
}

View File

@@ -1,564 +0,0 @@
package v2
import (
"errors"
"fmt"
"time"
"github.com/tendermint/tendermint/behaviour" //nolint:misspell
bc "github.com/tendermint/tendermint/blockchain"
"github.com/tendermint/tendermint/libs/log"
tmsync "github.com/tendermint/tendermint/libs/sync"
"github.com/tendermint/tendermint/p2p"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain"
"github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
const (
// chBufferSize is the buffer size of all event channels.
chBufferSize int = 1000
)
type blockStore interface {
LoadBlock(height int64) *types.Block
SaveBlock(*types.Block, *types.PartSet, *types.Commit)
Base() int64
Height() int64
}
// BlockchainReactor handles fast sync protocol.
type BlockchainReactor struct {
p2p.BaseReactor
fastSync bool // if true, enable fast sync on start
stateSynced bool // set to true when SwitchToFastSync is called by state sync
scheduler *Routine
processor *Routine
logger log.Logger
mtx tmsync.RWMutex
maxPeerHeight int64
syncHeight int64
events chan Event // non-nil during a fast sync
reporter behaviour.Reporter
io iIO
store blockStore
}
//nolint:unused,deadcode
type blockVerifier interface {
VerifyCommit(chainID string, blockID types.BlockID, height int64, commit *types.Commit) error
}
type blockApplier interface {
ApplyBlock(state state.State, blockID types.BlockID, block *types.Block) (state.State, int64, error)
}
// XXX: unify naming in this package around tmState
func newReactor(state state.State, store blockStore, reporter behaviour.Reporter,
blockApplier blockApplier, fastSync bool) *BlockchainReactor {
initHeight := state.LastBlockHeight + 1
if initHeight == 1 {
initHeight = state.InitialHeight
}
scheduler := newScheduler(initHeight, time.Now())
pContext := newProcessorContext(store, blockApplier, state)
// TODO: Fix naming to just newProcesssor
// newPcState requires a processorContext
processor := newPcState(pContext)
return &BlockchainReactor{
scheduler: newRoutine("scheduler", scheduler.handle, chBufferSize),
processor: newRoutine("processor", processor.handle, chBufferSize),
store: store,
reporter: reporter,
logger: log.NewNopLogger(),
fastSync: fastSync,
}
}
// NewBlockchainReactor creates a new reactor instance.
func NewBlockchainReactor(
state state.State,
blockApplier blockApplier,
store blockStore,
fastSync bool) *BlockchainReactor {
reporter := behaviour.NewMockReporter()
return newReactor(state, store, reporter, blockApplier, fastSync)
}
// SetSwitch implements Reactor interface.
func (r *BlockchainReactor) SetSwitch(sw *p2p.Switch) {
r.Switch = sw
if sw != nil {
r.io = newSwitchIo(sw)
} else {
r.io = nil
}
}
func (r *BlockchainReactor) setMaxPeerHeight(height int64) {
r.mtx.Lock()
defer r.mtx.Unlock()
if height > r.maxPeerHeight {
r.maxPeerHeight = height
}
}
func (r *BlockchainReactor) setSyncHeight(height int64) {
r.mtx.Lock()
defer r.mtx.Unlock()
r.syncHeight = height
}
// SyncHeight returns the height to which the BlockchainReactor has synced.
func (r *BlockchainReactor) SyncHeight() int64 {
r.mtx.RLock()
defer r.mtx.RUnlock()
return r.syncHeight
}
// SetLogger sets the logger of the reactor.
func (r *BlockchainReactor) SetLogger(logger log.Logger) {
r.logger = logger
r.scheduler.setLogger(logger)
r.processor.setLogger(logger)
}
// Start implements cmn.Service interface
func (r *BlockchainReactor) Start() error {
r.reporter = behaviour.NewSwitchReporter(r.BaseReactor.Switch)
if r.fastSync {
err := r.startSync(nil)
if err != nil {
return fmt.Errorf("failed to start fast sync: %w", err)
}
}
return nil
}
// startSync begins a fast sync, signaled by r.events being non-nil. If state is non-nil,
// the scheduler and processor is updated with this state on startup.
func (r *BlockchainReactor) startSync(state *state.State) error {
r.mtx.Lock()
defer r.mtx.Unlock()
if r.events != nil {
return errors.New("fast sync already in progress")
}
r.events = make(chan Event, chBufferSize)
go r.scheduler.start()
go r.processor.start()
if state != nil {
<-r.scheduler.ready()
<-r.processor.ready()
r.scheduler.send(bcResetState{state: *state})
r.processor.send(bcResetState{state: *state})
}
go r.demux(r.events)
return nil
}
// endSync ends a fast sync
func (r *BlockchainReactor) endSync() {
r.mtx.Lock()
defer r.mtx.Unlock()
if r.events != nil {
close(r.events)
}
r.events = nil
r.scheduler.stop()
r.processor.stop()
}
// SwitchToFastSync is called by the state sync reactor when switching to fast sync.
func (r *BlockchainReactor) SwitchToFastSync(state state.State) error {
r.stateSynced = true
state = state.Copy()
return r.startSync(&state)
}
// reactor generated ticker events:
// ticker for cleaning peers
type rTryPrunePeer struct {
priorityHigh
time time.Time
}
func (e rTryPrunePeer) String() string {
return fmt.Sprintf("rTryPrunePeer{%v}", e.time)
}
// ticker event for scheduling block requests
type rTrySchedule struct {
priorityHigh
time time.Time
}
func (e rTrySchedule) String() string {
return fmt.Sprintf("rTrySchedule{%v}", e.time)
}
// ticker for block processing
type rProcessBlock struct {
priorityNormal
}
func (e rProcessBlock) String() string {
return "rProcessBlock"
}
// reactor generated events based on blockchain related messages from peers:
// blockResponse message received from a peer
type bcBlockResponse struct {
priorityNormal
time time.Time
peerID p2p.ID
size int64
block *types.Block
}
func (resp bcBlockResponse) String() string {
return fmt.Sprintf("bcBlockResponse{%d#%X (size: %d bytes) from %v at %v}",
resp.block.Height, resp.block.Hash(), resp.size, resp.peerID, resp.time)
}
// blockNoResponse message received from a peer
type bcNoBlockResponse struct {
priorityNormal
time time.Time
peerID p2p.ID
height int64
}
func (resp bcNoBlockResponse) String() string {
return fmt.Sprintf("bcNoBlockResponse{%v has no block at height %d at %v}",
resp.peerID, resp.height, resp.time)
}
// statusResponse message received from a peer
type bcStatusResponse struct {
priorityNormal
time time.Time
peerID p2p.ID
base int64
height int64
}
func (resp bcStatusResponse) String() string {
return fmt.Sprintf("bcStatusResponse{%v is at height %d (base: %d) at %v}",
resp.peerID, resp.height, resp.base, resp.time)
}
// new peer is connected
type bcAddNewPeer struct {
priorityNormal
peerID p2p.ID
}
func (resp bcAddNewPeer) String() string {
return fmt.Sprintf("bcAddNewPeer{%v}", resp.peerID)
}
// existing peer is removed
type bcRemovePeer struct {
priorityHigh
peerID p2p.ID
reason interface{}
}
func (resp bcRemovePeer) String() string {
return fmt.Sprintf("bcRemovePeer{%v due to %v}", resp.peerID, resp.reason)
}
// resets the scheduler and processor state, e.g. following a switch from state syncing
type bcResetState struct {
priorityHigh
state state.State
}
func (e bcResetState) String() string {
return fmt.Sprintf("bcResetState{%v}", e.state)
}
// Takes the channel as a parameter to avoid race conditions on r.events.
func (r *BlockchainReactor) demux(events <-chan Event) {
var lastRate = 0.0
var lastHundred = time.Now()
var (
processBlockFreq = 20 * time.Millisecond
doProcessBlockCh = make(chan struct{}, 1)
doProcessBlockTk = time.NewTicker(processBlockFreq)
)
defer doProcessBlockTk.Stop()
var (
prunePeerFreq = 1 * time.Second
doPrunePeerCh = make(chan struct{}, 1)
doPrunePeerTk = time.NewTicker(prunePeerFreq)
)
defer doPrunePeerTk.Stop()
var (
scheduleFreq = 20 * time.Millisecond
doScheduleCh = make(chan struct{}, 1)
doScheduleTk = time.NewTicker(scheduleFreq)
)
defer doScheduleTk.Stop()
var (
statusFreq = 10 * time.Second
doStatusCh = make(chan struct{}, 1)
doStatusTk = time.NewTicker(statusFreq)
)
defer doStatusTk.Stop()
doStatusCh <- struct{}{} // immediately broadcast to get status of existing peers
// XXX: Extract timers to make testing atemporal
for {
select {
// Pacers: send at most per frequency but don't saturate
case <-doProcessBlockTk.C:
select {
case doProcessBlockCh <- struct{}{}:
default:
}
case <-doPrunePeerTk.C:
select {
case doPrunePeerCh <- struct{}{}:
default:
}
case <-doScheduleTk.C:
select {
case doScheduleCh <- struct{}{}:
default:
}
case <-doStatusTk.C:
select {
case doStatusCh <- struct{}{}:
default:
}
// Tickers: perform tasks periodically
case <-doScheduleCh:
r.scheduler.send(rTrySchedule{time: time.Now()})
case <-doPrunePeerCh:
r.scheduler.send(rTryPrunePeer{time: time.Now()})
case <-doProcessBlockCh:
r.processor.send(rProcessBlock{})
case <-doStatusCh:
if err := r.io.broadcastStatusRequest(); err != nil {
r.logger.Error("Error broadcasting status request", "err", err)
}
// Events from peers. Closing the channel signals event loop termination.
case event, ok := <-events:
if !ok {
r.logger.Info("Stopping event processing")
return
}
switch event := event.(type) {
case bcStatusResponse:
r.setMaxPeerHeight(event.height)
r.scheduler.send(event)
case bcAddNewPeer, bcRemovePeer, bcBlockResponse, bcNoBlockResponse:
r.scheduler.send(event)
default:
r.logger.Error("Received unexpected event", "event", fmt.Sprintf("%T", event))
}
// Incremental events from scheduler
case event := <-r.scheduler.next():
switch event := event.(type) {
case scBlockReceived:
r.processor.send(event)
case scPeerError:
r.processor.send(event)
if err := r.reporter.Report(behaviour.BadMessage(event.peerID, "scPeerError")); err != nil {
r.logger.Error("Error reporting peer", "err", err)
}
case scBlockRequest:
if err := r.io.sendBlockRequest(event.peerID, event.height); err != nil {
r.logger.Error("Error sending block request", "err", err)
}
case scFinishedEv:
r.processor.send(event)
r.scheduler.stop()
case scSchedulerFail:
r.logger.Error("Scheduler failure", "err", event.reason.Error())
case scPeersPruned:
// Remove peers from the processor.
for _, peerID := range event.peers {
r.processor.send(scPeerError{peerID: peerID, reason: errors.New("peer was pruned")})
}
r.logger.Debug("Pruned peers", "count", len(event.peers))
case noOpEvent:
default:
r.logger.Error("Received unexpected scheduler event", "event", fmt.Sprintf("%T", event))
}
// Incremental events from processor
case event := <-r.processor.next():
switch event := event.(type) {
case pcBlockProcessed:
r.setSyncHeight(event.height)
if r.syncHeight%100 == 0 {
lastRate = 0.9*lastRate + 0.1*(100/time.Since(lastHundred).Seconds())
r.logger.Info("Fast Sync Rate", "height", r.syncHeight,
"max_peer_height", r.maxPeerHeight, "blocks/s", lastRate)
lastHundred = time.Now()
}
r.scheduler.send(event)
case pcBlockVerificationFailure:
r.scheduler.send(event)
case pcFinished:
r.logger.Info("Fast sync complete, switching to consensus")
if !r.io.trySwitchToConsensus(event.tmState, event.blocksSynced > 0 || r.stateSynced) {
r.logger.Error("Failed to switch to consensus reactor")
}
r.endSync()
return
case noOpEvent:
default:
r.logger.Error("Received unexpected processor event", "event", fmt.Sprintf("%T", event))
}
// Terminal event from scheduler
case err := <-r.scheduler.final():
switch err {
case nil:
r.logger.Info("Scheduler stopped")
default:
r.logger.Error("Scheduler aborted with error", "err", err)
}
// Terminal event from processor
case err := <-r.processor.final():
switch err {
case nil:
r.logger.Info("Processor stopped")
default:
r.logger.Error("Processor aborted with error", "err", err)
}
}
}
}
// Stop implements cmn.Service interface.
func (r *BlockchainReactor) Stop() error {
r.logger.Info("reactor stopping")
r.endSync()
r.logger.Info("reactor stopped")
return nil
}
// Receive implements Reactor by handling different message types.
func (r *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
msg, err := bc.DecodeMsg(msgBytes)
if err != nil {
r.logger.Error("error decoding message",
"src", src.ID(), "chId", chID, "msg", msg, "err", err)
_ = r.reporter.Report(behaviour.BadMessage(src.ID(), err.Error()))
return
}
if err = bc.ValidateMsg(msg); err != nil {
r.logger.Error("peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
_ = r.reporter.Report(behaviour.BadMessage(src.ID(), err.Error()))
return
}
r.logger.Debug("Receive", "src", src.ID(), "chID", chID, "msg", msg)
switch msg := msg.(type) {
case *bcproto.StatusRequest:
if err := r.io.sendStatusResponse(r.store.Base(), r.store.Height(), src.ID()); err != nil {
r.logger.Error("Could not send status message to peer", "src", src)
}
case *bcproto.BlockRequest:
block := r.store.LoadBlock(msg.Height)
if block != nil {
if err = r.io.sendBlockToPeer(block, src.ID()); err != nil {
r.logger.Error("Could not send block message to peer: ", err)
}
} else {
r.logger.Info("peer asking for a block we don't have", "src", src, "height", msg.Height)
peerID := src.ID()
if err = r.io.sendBlockNotFound(msg.Height, peerID); err != nil {
r.logger.Error("Couldn't send block not found: ", err)
}
}
case *bcproto.StatusResponse:
r.mtx.RLock()
if r.events != nil {
r.events <- bcStatusResponse{peerID: src.ID(), base: msg.Base, height: msg.Height}
}
r.mtx.RUnlock()
case *bcproto.BlockResponse:
bi, err := types.BlockFromProto(msg.Block)
if err != nil {
r.logger.Error("error transitioning block from protobuf", "err", err)
return
}
r.mtx.RLock()
if r.events != nil {
r.events <- bcBlockResponse{
peerID: src.ID(),
block: bi,
size: int64(len(msgBytes)),
time: time.Now(),
}
}
r.mtx.RUnlock()
case *bcproto.NoBlockResponse:
r.mtx.RLock()
if r.events != nil {
r.events <- bcNoBlockResponse{peerID: src.ID(), height: msg.Height, time: time.Now()}
}
r.mtx.RUnlock()
}
}
// AddPeer implements Reactor interface
func (r *BlockchainReactor) AddPeer(peer p2p.Peer) {
err := r.io.sendStatusResponse(r.store.Base(), r.store.Height(), peer.ID())
if err != nil {
r.logger.Error("Could not send status message to peer new", "src", peer.ID, "height", r.SyncHeight())
}
r.mtx.RLock()
defer r.mtx.RUnlock()
if r.events != nil {
r.events <- bcAddNewPeer{peerID: peer.ID()}
}
}
// RemovePeer implements Reactor interface.
func (r *BlockchainReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
r.mtx.RLock()
defer r.mtx.RUnlock()
if r.events != nil {
r.events <- bcRemovePeer{
peerID: peer.ID(),
reason: reason,
}
}
}
// GetChannels implements Reactor
func (r *BlockchainReactor) GetChannels() []*p2p.ChannelDescriptor {
return []*p2p.ChannelDescriptor{
{
ID: BlockchainChannel,
Priority: 5,
SendQueueCapacity: 2000,
RecvBufferCapacity: 50 * 4096,
RecvMessageCapacity: bc.MaxMsgSize,
},
}
}

View File

@@ -1,569 +0,0 @@
package v2
import (
"fmt"
"net"
"os"
"sort"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tm-db"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/behaviour" //nolint:misspell
bc "github.com/tendermint/tendermint/blockchain"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/libs/service"
mpmocks "github.com/tendermint/tendermint/mempool/mocks"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/p2p/conn"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
)
type mockPeer struct {
service.Service
id p2p.ID
}
func (mp mockPeer) FlushStop() {}
func (mp mockPeer) ID() p2p.ID { return mp.id }
func (mp mockPeer) RemoteIP() net.IP { return net.IP{} }
func (mp mockPeer) RemoteAddr() net.Addr { return &net.TCPAddr{IP: mp.RemoteIP(), Port: 8800} }
func (mp mockPeer) IsOutbound() bool { return true }
func (mp mockPeer) IsPersistent() bool { return true }
func (mp mockPeer) CloseConn() error { return nil }
func (mp mockPeer) NodeInfo() p2p.NodeInfo {
return p2p.DefaultNodeInfo{
DefaultNodeID: "",
ListenAddr: "",
}
}
func (mp mockPeer) Status() conn.ConnectionStatus { return conn.ConnectionStatus{} }
func (mp mockPeer) SocketAddr() *p2p.NetAddress { return &p2p.NetAddress{} }
func (mp mockPeer) Send(byte, []byte) bool { return true }
func (mp mockPeer) TrySend(byte, []byte) bool { return true }
func (mp mockPeer) Set(string, interface{}) {}
func (mp mockPeer) Get(string) interface{} { return struct{}{} }
// nolint:unused // ignore
type mockBlockStore struct {
blocks map[int64]*types.Block
}
// nolint:unused // ignore
func (ml *mockBlockStore) Height() int64 {
return int64(len(ml.blocks))
}
// nolint:unused // ignore
func (ml *mockBlockStore) LoadBlock(height int64) *types.Block {
return ml.blocks[height]
}
// nolint:unused // ignore
func (ml *mockBlockStore) SaveBlock(block *types.Block, part *types.PartSet, commit *types.Commit) {
ml.blocks[block.Height] = block
}
type mockBlockApplier struct {
}
// XXX: Add whitelist/blacklist?
func (mba *mockBlockApplier) ApplyBlock(
state sm.State, blockID types.BlockID, block *types.Block,
) (sm.State, int64, error) {
state.LastBlockHeight++
return state, 0, nil
}
type mockSwitchIo struct {
mtx sync.Mutex
switchedToConsensus bool
numStatusResponse int
numBlockResponse int
numNoBlockResponse int
}
func (sio *mockSwitchIo) sendBlockRequest(peerID p2p.ID, height int64) error {
return nil
}
func (sio *mockSwitchIo) sendStatusResponse(base, height int64, peerID p2p.ID) error {
sio.mtx.Lock()
defer sio.mtx.Unlock()
sio.numStatusResponse++
return nil
}
func (sio *mockSwitchIo) sendBlockToPeer(block *types.Block, peerID p2p.ID) error {
sio.mtx.Lock()
defer sio.mtx.Unlock()
sio.numBlockResponse++
return nil
}
func (sio *mockSwitchIo) sendBlockNotFound(height int64, peerID p2p.ID) error {
sio.mtx.Lock()
defer sio.mtx.Unlock()
sio.numNoBlockResponse++
return nil
}
func (sio *mockSwitchIo) trySwitchToConsensus(state sm.State, skipWAL bool) bool {
sio.mtx.Lock()
defer sio.mtx.Unlock()
sio.switchedToConsensus = true
return true
}
func (sio *mockSwitchIo) broadcastStatusRequest() error {
return nil
}
type testReactorParams struct {
logger log.Logger
genDoc *types.GenesisDoc
privVals []types.PrivValidator
startHeight int64
mockA bool
}
func newTestReactor(t *testing.T, p testReactorParams) *BlockchainReactor {
store, state, _ := newReactorStore(t, p.genDoc, p.privVals, p.startHeight)
reporter := behaviour.NewMockReporter()
var appl blockApplier
if p.mockA {
appl = &mockBlockApplier{}
} else {
mp := &mpmocks.Mempool{}
mp.On("Lock").Return()
mp.On("Unlock").Return()
mp.On("FlushAppConn", mock.Anything).Return(nil)
mp.On("Update",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything).Return(nil)
app := &testApp{}
cc := proxy.NewLocalClientCreator(app)
proxyApp := proxy.NewAppConns(cc)
err := proxyApp.Start()
if err != nil {
panic(fmt.Errorf("error start app: %w", err))
}
db := dbm.NewMemDB()
stateStore := sm.NewStore(db)
appl = sm.NewBlockExecutor(stateStore, p.logger, proxyApp.Consensus(), mp, sm.EmptyEvidencePool{})
if err = stateStore.Save(state); err != nil {
panic(err)
}
}
r := newReactor(state, store, reporter, appl, true)
logger := log.TestingLogger()
r.SetLogger(logger.With("module", "blockchain"))
return r
}
// This test is left here and not deleted to retain the termination cases for
// future improvement in [#4482](https://github.com/tendermint/tendermint/issues/4482).
// func TestReactorTerminationScenarios(t *testing.T) {
// config := cfg.ResetTestRoot("blockchain_reactor_v2_test")
// defer os.RemoveAll(config.RootDir)
// genDoc, privVals := randGenesisDoc(config.ChainID(), 1, false, 30)
// refStore, _, _ := newReactorStore(genDoc, privVals, 20)
// params := testReactorParams{
// logger: log.TestingLogger(),
// genDoc: genDoc,
// privVals: privVals,
// startHeight: 10,
// bufferSize: 100,
// mockA: true,
// }
// type testEvent struct {
// evType string
// peer string
// height int64
// }
// tests := []struct {
// name string
// params testReactorParams
// msgs []testEvent
// }{
// {
// name: "simple termination on max peer height - one peer",
// params: params,
// msgs: []testEvent{
// {evType: "AddPeer", peer: "P1"},
// {evType: "ReceiveS", peer: "P1", height: 13},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P1", height: 11},
// {evType: "BlockReq"},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P1", height: 12},
// {evType: "Process"},
// {evType: "ReceiveB", peer: "P1", height: 13},
// {evType: "Process"},
// },
// },
// {
// name: "simple termination on max peer height - two peers",
// params: params,
// msgs: []testEvent{
// {evType: "AddPeer", peer: "P1"},
// {evType: "AddPeer", peer: "P2"},
// {evType: "ReceiveS", peer: "P1", height: 13},
// {evType: "ReceiveS", peer: "P2", height: 15},
// {evType: "BlockReq"},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P1", height: 11},
// {evType: "ReceiveB", peer: "P2", height: 12},
// {evType: "Process"},
// {evType: "BlockReq"},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P1", height: 13},
// {evType: "Process"},
// {evType: "ReceiveB", peer: "P2", height: 14},
// {evType: "Process"},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P2", height: 15},
// {evType: "Process"},
// },
// },
// {
// name: "termination on max peer height - two peers, noBlock error",
// params: params,
// msgs: []testEvent{
// {evType: "AddPeer", peer: "P1"},
// {evType: "AddPeer", peer: "P2"},
// {evType: "ReceiveS", peer: "P1", height: 13},
// {evType: "ReceiveS", peer: "P2", height: 15},
// {evType: "BlockReq"},
// {evType: "BlockReq"},
// {evType: "ReceiveNB", peer: "P1", height: 11},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P2", height: 12},
// {evType: "ReceiveB", peer: "P2", height: 11},
// {evType: "Process"},
// {evType: "BlockReq"},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P2", height: 13},
// {evType: "Process"},
// {evType: "ReceiveB", peer: "P2", height: 14},
// {evType: "Process"},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P2", height: 15},
// {evType: "Process"},
// },
// },
// {
// name: "termination on max peer height - two peers, remove one peer",
// params: params,
// msgs: []testEvent{
// {evType: "AddPeer", peer: "P1"},
// {evType: "AddPeer", peer: "P2"},
// {evType: "ReceiveS", peer: "P1", height: 13},
// {evType: "ReceiveS", peer: "P2", height: 15},
// {evType: "BlockReq"},
// {evType: "BlockReq"},
// {evType: "RemovePeer", peer: "P1"},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P2", height: 12},
// {evType: "ReceiveB", peer: "P2", height: 11},
// {evType: "Process"},
// {evType: "BlockReq"},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P2", height: 13},
// {evType: "Process"},
// {evType: "ReceiveB", peer: "P2", height: 14},
// {evType: "Process"},
// {evType: "BlockReq"},
// {evType: "ReceiveB", peer: "P2", height: 15},
// {evType: "Process"},
// },
// },
// }
// for _, tt := range tests {
// tt := tt
// t.Run(tt.name, func(t *testing.T) {
// reactor := newTestReactor(params)
// reactor.Start()
// reactor.reporter = behavior.NewMockReporter()
// mockSwitch := &mockSwitchIo{switchedToConsensus: false}
// reactor.io = mockSwitch
// // time for go routines to start
// time.Sleep(time.Millisecond)
// for _, step := range tt.msgs {
// switch step.evType {
// case "AddPeer":
// reactor.scheduler.send(bcAddNewPeer{peerID: p2p.ID(step.peer)})
// case "RemovePeer":
// reactor.scheduler.send(bcRemovePeer{peerID: p2p.ID(step.peer)})
// case "ReceiveS":
// reactor.scheduler.send(bcStatusResponse{
// peerID: p2p.ID(step.peer),
// height: step.height,
// time: time.Now(),
// })
// case "ReceiveB":
// reactor.scheduler.send(bcBlockResponse{
// peerID: p2p.ID(step.peer),
// block: refStore.LoadBlock(step.height),
// size: 10,
// time: time.Now(),
// })
// case "ReceiveNB":
// reactor.scheduler.send(bcNoBlockResponse{
// peerID: p2p.ID(step.peer),
// height: step.height,
// time: time.Now(),
// })
// case "BlockReq":
// reactor.scheduler.send(rTrySchedule{time: time.Now()})
// case "Process":
// reactor.processor.send(rProcessBlock{})
// }
// // give time for messages to propagate between routines
// time.Sleep(time.Millisecond)
// }
// // time for processor to finish and reactor to switch to consensus
// time.Sleep(20 * time.Millisecond)
// assert.True(t, mockSwitch.hasSwitchedToConsensus())
// reactor.Stop()
// })
// }
// }
func TestReactorHelperMode(t *testing.T) {
var (
channelID = byte(0x40)
)
config := cfg.ResetTestRoot("blockchain_reactor_v2_test")
defer os.RemoveAll(config.RootDir)
genDoc, privVals := randGenesisDoc(config.ChainID(), 1, false, 30)
params := testReactorParams{
logger: log.TestingLogger(),
genDoc: genDoc,
privVals: privVals,
startHeight: 20,
mockA: true,
}
type testEvent struct {
peer string
event interface{}
}
tests := []struct {
name string
params testReactorParams
msgs []testEvent
}{
{
name: "status request",
params: params,
msgs: []testEvent{
{"P1", bcproto.StatusRequest{}},
{"P1", bcproto.BlockRequest{Height: 13}},
{"P1", bcproto.BlockRequest{Height: 20}},
{"P1", bcproto.BlockRequest{Height: 22}},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
reactor := newTestReactor(t, params)
mockSwitch := &mockSwitchIo{switchedToConsensus: false}
reactor.io = mockSwitch
err := reactor.Start()
require.NoError(t, err)
for i := 0; i < len(tt.msgs); i++ {
step := tt.msgs[i]
switch ev := step.event.(type) {
case bcproto.StatusRequest:
old := mockSwitch.numStatusResponse
msg, err := bc.EncodeMsg(&ev)
assert.NoError(t, err)
reactor.Receive(channelID, mockPeer{id: p2p.ID(step.peer)}, msg)
assert.Equal(t, old+1, mockSwitch.numStatusResponse)
case bcproto.BlockRequest:
if ev.Height > params.startHeight {
old := mockSwitch.numNoBlockResponse
msg, err := bc.EncodeMsg(&ev)
assert.NoError(t, err)
reactor.Receive(channelID, mockPeer{id: p2p.ID(step.peer)}, msg)
assert.Equal(t, old+1, mockSwitch.numNoBlockResponse)
} else {
old := mockSwitch.numBlockResponse
msg, err := bc.EncodeMsg(&ev)
assert.NoError(t, err)
assert.NoError(t, err)
reactor.Receive(channelID, mockPeer{id: p2p.ID(step.peer)}, msg)
assert.Equal(t, old+1, mockSwitch.numBlockResponse)
}
}
}
err = reactor.Stop()
require.NoError(t, err)
})
}
}
func TestReactorSetSwitchNil(t *testing.T) {
config := cfg.ResetTestRoot("blockchain_reactor_v2_test")
defer os.RemoveAll(config.RootDir)
genDoc, privVals := randGenesisDoc(config.ChainID(), 1, false, 30)
reactor := newTestReactor(t, testReactorParams{
logger: log.TestingLogger(),
genDoc: genDoc,
privVals: privVals,
})
reactor.SetSwitch(nil)
assert.Nil(t, reactor.Switch)
assert.Nil(t, reactor.io)
}
type testApp struct {
abci.BaseApplication
}
func randGenesisDoc(chainID string, numValidators int, randPower bool, minPower int64) (
*types.GenesisDoc, []types.PrivValidator) {
validators := make([]types.GenesisValidator, numValidators)
privValidators := make([]types.PrivValidator, numValidators)
for i := 0; i < numValidators; i++ {
val, privVal := types.RandValidator(randPower, minPower)
validators[i] = types.GenesisValidator{
PubKey: val.PubKey,
Power: val.VotingPower,
}
privValidators[i] = privVal
}
sort.Sort(types.PrivValidatorsByAddress(privValidators))
return &types.GenesisDoc{
GenesisTime: tmtime.Now(),
ChainID: chainID,
Validators: validators,
}, privValidators
}
// Why are we importing the entire blockExecutor dependency graph here
// when we have the facilities to
func newReactorStore(
t *testing.T,
genDoc *types.GenesisDoc,
privVals []types.PrivValidator,
maxBlockHeight int64) (*store.BlockStore, sm.State, *sm.BlockExecutor) {
if len(privVals) != 1 {
panic("only support one validator")
}
app := &testApp{}
cc := proxy.NewLocalClientCreator(app)
proxyApp := proxy.NewAppConns(cc)
err := proxyApp.Start()
if err != nil {
panic(fmt.Errorf("error start app: %w", err))
}
stateDB := dbm.NewMemDB()
blockStore := store.NewBlockStore(dbm.NewMemDB())
stateStore := sm.NewStore(stateDB)
state, err := stateStore.LoadFromDBOrGenesisDoc(genDoc)
if err != nil {
panic(fmt.Errorf("error constructing state from genesis file: %w", err))
}
mp := &mpmocks.Mempool{}
mp.On("Lock").Return()
mp.On("Unlock").Return()
mp.On("FlushAppConn", mock.Anything).Return(nil)
mp.On("Update",
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything).Return(nil)
db := dbm.NewMemDB()
stateStore = sm.NewStore(db)
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
mp, sm.EmptyEvidencePool{})
if err = stateStore.Save(state); err != nil {
panic(err)
}
// add blocks in
for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ {
lastCommit := types.NewCommit(blockHeight-1, 0, types.BlockID{}, nil)
if blockHeight > 1 {
lastBlockMeta := blockStore.LoadBlockMeta(blockHeight - 1)
lastBlock := blockStore.LoadBlock(blockHeight - 1)
vote, err := types.MakeVote(
lastBlock.Header.Height,
lastBlockMeta.BlockID,
state.Validators,
privVals[0],
lastBlock.Header.ChainID,
time.Now(),
)
if err != nil {
panic(err)
}
lastCommit = types.NewCommit(vote.Height, vote.Round,
lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()})
}
thisBlock := sf.MakeBlock(state, blockHeight, lastCommit)
thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes)
require.NoError(t, err)
blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()}
state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock)
if err != nil {
panic(fmt.Errorf("error apply block: %w", err))
}
blockStore.SaveBlock(thisBlock, thisParts, lastCommit)
}
return blockStore, state, blockExec
}

View File

@@ -1,166 +0,0 @@
package v2
import (
"fmt"
"strings"
"sync/atomic"
"github.com/Workiva/go-datastructures/queue"
"github.com/tendermint/tendermint/libs/log"
)
type handleFunc = func(event Event) (Event, error)
const historySize = 25
// Routine is a structure that models a finite state machine as serialized
// stream of events processed by a handle function. This Routine structure
// handles the concurrency and messaging guarantees. Events are sent via
// `send` are handled by the `handle` function to produce an iterator
// `next()`. Calling `stop()` on a routine will conclude processing of all
// sent events and produce `final()` event representing the terminal state.
type Routine struct {
name string
handle handleFunc
queue *queue.PriorityQueue
history []Event
out chan Event
fin chan error
rdy chan struct{}
running *uint32
logger log.Logger
metrics *Metrics
}
func newRoutine(name string, handleFunc handleFunc, bufferSize int) *Routine {
return &Routine{
name: name,
handle: handleFunc,
queue: queue.NewPriorityQueue(bufferSize, true),
history: make([]Event, 0, historySize),
out: make(chan Event, bufferSize),
rdy: make(chan struct{}, 1),
fin: make(chan error, 1),
running: new(uint32),
logger: log.NewNopLogger(),
metrics: NopMetrics(),
}
}
func (rt *Routine) setLogger(logger log.Logger) {
rt.logger = logger
}
// nolint:unused
func (rt *Routine) setMetrics(metrics *Metrics) {
rt.metrics = metrics
}
func (rt *Routine) start() {
rt.logger.Info("routine start", "msg", log.NewLazySprintf("%s: run", rt.name))
running := atomic.CompareAndSwapUint32(rt.running, uint32(0), uint32(1))
if !running {
panic(fmt.Sprintf("%s is already running", rt.name))
}
close(rt.rdy)
defer func() {
if r := recover(); r != nil {
var (
b strings.Builder
j int
)
for i := len(rt.history) - 1; i >= 0; i-- {
fmt.Fprintf(&b, "%d: %+v\n", j, rt.history[i])
j++
}
panic(fmt.Sprintf("%v\nlast events:\n%v", r, b.String()))
}
stopped := atomic.CompareAndSwapUint32(rt.running, uint32(1), uint32(0))
if !stopped {
panic(fmt.Sprintf("%s is failed to stop", rt.name))
}
}()
for {
events, err := rt.queue.Get(1)
if err == queue.ErrDisposed {
rt.terminate(nil)
return
} else if err != nil {
rt.terminate(err)
return
}
oEvent, err := rt.handle(events[0].(Event))
rt.metrics.EventsHandled.With("routine", rt.name).Add(1)
if err != nil {
rt.terminate(err)
return
}
rt.metrics.EventsOut.With("routine", rt.name).Add(1)
rt.logger.Debug("routine start", "msg", log.NewLazySprintf("%s: produced %T %+v", rt.name, oEvent, oEvent))
// Skip rTrySchedule and rProcessBlock events as they clutter the history
// due to their frequency.
switch events[0].(type) {
case rTrySchedule:
case rProcessBlock:
default:
rt.history = append(rt.history, events[0].(Event))
if len(rt.history) > historySize {
rt.history = rt.history[1:]
}
}
rt.out <- oEvent
}
}
// XXX: look into returning OpError in the net package
func (rt *Routine) send(event Event) bool {
rt.logger.Debug("routine send", "msg", log.NewLazySprintf("%s: received %T %+v", rt.name, event, event))
if !rt.isRunning() {
return false
}
err := rt.queue.Put(event)
if err != nil {
rt.metrics.EventsShed.With("routine", rt.name).Add(1)
rt.logger.Error(fmt.Sprintf("%s: send failed, queue was full/stopped", rt.name))
return false
}
rt.metrics.EventsSent.With("routine", rt.name).Add(1)
return true
}
func (rt *Routine) isRunning() bool {
return atomic.LoadUint32(rt.running) == 1
}
func (rt *Routine) next() chan Event {
return rt.out
}
func (rt *Routine) ready() chan struct{} {
return rt.rdy
}
func (rt *Routine) stop() {
if !rt.isRunning() { // XXX: this should check rt.queue.Disposed()
return
}
rt.logger.Info("routine stop", "msg", log.NewLazySprintf("%s: stop", rt.name))
rt.queue.Dispose() // this should block until all queue items are free?
}
func (rt *Routine) final() chan error {
return rt.fin
}
// XXX: Maybe get rid of this
func (rt *Routine) terminate(reason error) {
// We don't close the rt.out channel here, to avoid spinning on the closed channel
// in the event loop.
rt.fin <- reason
}

View File

@@ -1,163 +0,0 @@
package v2
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type eventA struct {
priorityNormal
}
var errDone = fmt.Errorf("done")
func simpleHandler(event Event) (Event, error) {
if _, ok := event.(eventA); ok {
return noOp, errDone
}
return noOp, nil
}
func TestRoutineFinal(t *testing.T) {
var (
bufferSize = 10
routine = newRoutine("simpleRoutine", simpleHandler, bufferSize)
)
assert.False(t, routine.isRunning(),
"expected an initialized routine to not be running")
go routine.start()
<-routine.ready()
assert.True(t, routine.isRunning(),
"expected an started routine")
assert.True(t, routine.send(eventA{}),
"expected sending to a ready routine to succeed")
assert.Equal(t, errDone, <-routine.final(),
"expected the final event to be done")
assert.False(t, routine.isRunning(),
"expected an completed routine to no longer be running")
}
func TestRoutineStop(t *testing.T) {
var (
bufferSize = 10
routine = newRoutine("simpleRoutine", simpleHandler, bufferSize)
)
assert.False(t, routine.send(eventA{}),
"expected sending to an unstarted routine to fail")
go routine.start()
<-routine.ready()
assert.True(t, routine.send(eventA{}),
"expected sending to a running routine to succeed")
routine.stop()
assert.False(t, routine.send(eventA{}),
"expected sending to a stopped routine to fail")
}
type finalCount struct {
count int
}
func (f finalCount) Error() string {
return "end"
}
func genStatefulHandler(maxCount int) handleFunc {
counter := 0
return func(event Event) (Event, error) {
if _, ok := event.(eventA); ok {
counter++
if counter >= maxCount {
return noOp, finalCount{counter}
}
return eventA{}, nil
}
return noOp, nil
}
}
func feedback(r *Routine) {
for event := range r.next() {
r.send(event)
}
}
func TestStatefulRoutine(t *testing.T) {
var (
count = 10
handler = genStatefulHandler(count)
bufferSize = 20
routine = newRoutine("statefulRoutine", handler, bufferSize)
)
go routine.start()
go feedback(routine)
<-routine.ready()
assert.True(t, routine.send(eventA{}),
"expected sending to a started routine to succeed")
final := <-routine.final()
if fnl, ok := final.(finalCount); ok {
assert.Equal(t, count, fnl.count,
"expected the routine to count to 10")
} else {
t.Fail()
}
}
type lowPriorityEvent struct {
priorityLow
}
type highPriorityEvent struct {
priorityHigh
}
func handleWithPriority(event Event) (Event, error) {
switch event.(type) {
case lowPriorityEvent:
return noOp, nil
case highPriorityEvent:
return noOp, errDone
}
return noOp, nil
}
func TestPriority(t *testing.T) {
var (
bufferSize = 20
routine = newRoutine("priorityRoutine", handleWithPriority, bufferSize)
)
go routine.start()
<-routine.ready()
go func() {
for {
routine.send(lowPriorityEvent{})
time.Sleep(1 * time.Millisecond)
}
}()
time.Sleep(10 * time.Millisecond)
assert.True(t, routine.isRunning(),
"expected an started routine")
assert.True(t, routine.send(highPriorityEvent{}),
"expected send to succeed even when saturated")
assert.Equal(t, errDone, <-routine.final())
assert.False(t, routine.isRunning(),
"expected an started routine")
}

View File

@@ -1,712 +0,0 @@
package v2
import (
"bytes"
"errors"
"fmt"
"math"
"sort"
"time"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
// Events generated by the scheduler:
// all blocks have been processed
type scFinishedEv struct {
priorityNormal
reason string
}
func (e scFinishedEv) String() string {
return fmt.Sprintf("scFinishedEv{%v}", e.reason)
}
// send a blockRequest message
type scBlockRequest struct {
priorityNormal
peerID p2p.ID
height int64
}
func (e scBlockRequest) String() string {
return fmt.Sprintf("scBlockRequest{%d from %v}", e.height, e.peerID)
}
// a block has been received and validated by the scheduler
type scBlockReceived struct {
priorityNormal
peerID p2p.ID
block *types.Block
}
func (e scBlockReceived) String() string {
return fmt.Sprintf("scBlockReceived{%d#%X from %v}", e.block.Height, e.block.Hash(), e.peerID)
}
// scheduler detected a peer error
type scPeerError struct {
priorityHigh
peerID p2p.ID
reason error
}
func (e scPeerError) String() string {
return fmt.Sprintf("scPeerError{%v errored with %v}", e.peerID, e.reason)
}
// scheduler removed a set of peers (timed out or slow peer)
type scPeersPruned struct {
priorityHigh
peers []p2p.ID
}
func (e scPeersPruned) String() string {
return fmt.Sprintf("scPeersPruned{%v}", e.peers)
}
// XXX: make this fatal?
// scheduler encountered a fatal error
type scSchedulerFail struct {
priorityHigh
reason error
}
func (e scSchedulerFail) String() string {
return fmt.Sprintf("scSchedulerFail{%v}", e.reason)
}
type blockState int
const (
blockStateUnknown blockState = iota + 1 // no known peer has this block
blockStateNew // indicates that a peer has reported having this block
blockStatePending // indicates that this block has been requested from a peer
blockStateReceived // indicates that this block has been received by a peer
blockStateProcessed // indicates that this block has been applied
)
func (e blockState) String() string {
switch e {
case blockStateUnknown:
return "Unknown"
case blockStateNew:
return "New"
case blockStatePending:
return "Pending"
case blockStateReceived:
return "Received"
case blockStateProcessed:
return "Processed"
default:
return fmt.Sprintf("invalid blockState: %d", e)
}
}
type peerState int
const (
peerStateNew = iota + 1
peerStateReady
peerStateRemoved
)
func (e peerState) String() string {
switch e {
case peerStateNew:
return "New"
case peerStateReady:
return "Ready"
case peerStateRemoved:
return "Removed"
default:
panic(fmt.Sprintf("unknown peerState: %d", e))
}
}
type scPeer struct {
peerID p2p.ID
// initialized as New when peer is added, updated to Ready when statusUpdate is received,
// updated to Removed when peer is removed
state peerState
base int64 // updated when statusResponse is received
height int64 // updated when statusResponse is received
lastTouched time.Time
lastRate int64 // last receive rate in bytes
}
func (p scPeer) String() string {
return fmt.Sprintf("{state %v, base %d, height %d, lastTouched %v, lastRate %d, id %v}",
p.state, p.base, p.height, p.lastTouched, p.lastRate, p.peerID)
}
func newScPeer(peerID p2p.ID) *scPeer {
return &scPeer{
peerID: peerID,
state: peerStateNew,
base: -1,
height: -1,
lastTouched: time.Time{},
}
}
// The scheduler keep track of the state of each block and each peer. The
// scheduler will attempt to schedule new block requests with `trySchedule`
// events and remove slow peers with `tryPrune` events.
type scheduler struct {
initHeight int64
// next block that needs to be processed. All blocks with smaller height are
// in Processed state.
height int64
// lastAdvance tracks the last time a block execution happened.
// syncTimeout is the maximum time the scheduler waits to advance in the fast sync process before finishing.
// This covers the cases where there are no peers or all peers have a lower height.
lastAdvance time.Time
syncTimeout time.Duration
// a map of peerID to scheduler specific peer struct `scPeer` used to keep
// track of peer specific state
peers map[p2p.ID]*scPeer
peerTimeout time.Duration // maximum response time from a peer otherwise prune
minRecvRate int64 // minimum receive rate from peer otherwise prune
// the maximum number of blocks that should be New, Received or Pending at any point
// in time. This is used to enforce a limit on the blockStates map.
targetPending int
// a list of blocks to be scheduled (New), Pending or Received. Its length should be
// smaller than targetPending.
blockStates map[int64]blockState
// a map of heights to the peer we are waiting a response from
pendingBlocks map[int64]p2p.ID
// the time at which a block was put in blockStatePending
pendingTime map[int64]time.Time
// a map of heights to the peers that put the block in blockStateReceived
receivedBlocks map[int64]p2p.ID
}
func (sc scheduler) String() string {
return fmt.Sprintf("ih: %d, bst: %v, peers: %v, pblks: %v, ptm %v, rblks: %v",
sc.initHeight, sc.blockStates, sc.peers, sc.pendingBlocks, sc.pendingTime, sc.receivedBlocks)
}
func newScheduler(initHeight int64, startTime time.Time) *scheduler {
sc := scheduler{
initHeight: initHeight,
lastAdvance: startTime,
syncTimeout: 60 * time.Second,
height: initHeight,
blockStates: make(map[int64]blockState),
peers: make(map[p2p.ID]*scPeer),
pendingBlocks: make(map[int64]p2p.ID),
pendingTime: make(map[int64]time.Time),
receivedBlocks: make(map[int64]p2p.ID),
targetPending: 10, // TODO - pass as param
peerTimeout: 15 * time.Second, // TODO - pass as param
minRecvRate: 0, // int64(7680), TODO - pass as param
}
return &sc
}
func (sc *scheduler) ensurePeer(peerID p2p.ID) *scPeer {
if _, ok := sc.peers[peerID]; !ok {
sc.peers[peerID] = newScPeer(peerID)
}
return sc.peers[peerID]
}
func (sc *scheduler) touchPeer(peerID p2p.ID, time time.Time) error {
peer, ok := sc.peers[peerID]
if !ok {
return fmt.Errorf("couldn't find peer %s", peerID)
}
if peer.state != peerStateReady {
return fmt.Errorf("tried to touch peer in state %s, must be Ready", peer.state)
}
peer.lastTouched = time
return nil
}
func (sc *scheduler) removePeer(peerID p2p.ID) {
peer, ok := sc.peers[peerID]
if !ok {
return
}
if peer.state == peerStateRemoved {
return
}
for height, pendingPeerID := range sc.pendingBlocks {
if pendingPeerID == peerID {
sc.setStateAtHeight(height, blockStateNew)
delete(sc.pendingTime, height)
delete(sc.pendingBlocks, height)
}
}
for height, rcvPeerID := range sc.receivedBlocks {
if rcvPeerID == peerID {
sc.setStateAtHeight(height, blockStateNew)
delete(sc.receivedBlocks, height)
}
}
// remove the blocks from blockStates if the peer removal causes the max peer height to be lower.
peer.state = peerStateRemoved
maxPeerHeight := int64(0)
for _, otherPeer := range sc.peers {
if otherPeer.state != peerStateReady {
continue
}
if otherPeer.peerID != peer.peerID && otherPeer.height > maxPeerHeight {
maxPeerHeight = otherPeer.height
}
}
for h := range sc.blockStates {
if h > maxPeerHeight {
delete(sc.blockStates, h)
}
}
}
// check if the blockPool is running low and add new blocks in New state to be requested.
// This function is called when there is an increase in the maximum peer height or when
// blocks are processed.
func (sc *scheduler) addNewBlocks() {
if len(sc.blockStates) >= sc.targetPending {
return
}
for i := sc.height; i < int64(sc.targetPending)+sc.height; i++ {
if i > sc.maxHeight() {
break
}
if sc.getStateAtHeight(i) == blockStateUnknown {
sc.setStateAtHeight(i, blockStateNew)
}
}
}
func (sc *scheduler) setPeerRange(peerID p2p.ID, base int64, height int64) error {
peer := sc.ensurePeer(peerID)
if peer.state == peerStateRemoved {
return nil // noop
}
if height < peer.height {
sc.removePeer(peerID)
return fmt.Errorf("cannot move peer height lower. from %d to %d", peer.height, height)
}
if base > height {
sc.removePeer(peerID)
return fmt.Errorf("cannot set peer base higher than its height")
}
peer.base = base
peer.height = height
peer.state = peerStateReady
sc.addNewBlocks()
return nil
}
func (sc *scheduler) getStateAtHeight(height int64) blockState {
if height < sc.height {
return blockStateProcessed
} else if state, ok := sc.blockStates[height]; ok {
return state
} else {
return blockStateUnknown
}
}
func (sc *scheduler) getPeersWithHeight(height int64) []p2p.ID {
peers := make([]p2p.ID, 0)
for _, peer := range sc.peers {
if peer.state != peerStateReady {
continue
}
if peer.base <= height && peer.height >= height {
peers = append(peers, peer.peerID)
}
}
return peers
}
func (sc *scheduler) prunablePeers(peerTimout time.Duration, minRecvRate int64, now time.Time) []p2p.ID {
prunable := make([]p2p.ID, 0)
for peerID, peer := range sc.peers {
if peer.state != peerStateReady {
continue
}
if now.Sub(peer.lastTouched) > peerTimout || peer.lastRate < minRecvRate {
prunable = append(prunable, peerID)
}
}
// Tests for handleTryPrunePeer() may fail without sort due to range non-determinism
sort.Sort(PeerByID(prunable))
return prunable
}
func (sc *scheduler) setStateAtHeight(height int64, state blockState) {
sc.blockStates[height] = state
}
// CONTRACT: peer exists and in Ready state.
func (sc *scheduler) markReceived(peerID p2p.ID, height int64, size int64, now time.Time) error {
peer := sc.peers[peerID]
if state := sc.getStateAtHeight(height); state != blockStatePending || sc.pendingBlocks[height] != peerID {
return fmt.Errorf("received block %d from peer %s without being requested", height, peerID)
}
pendingTime, ok := sc.pendingTime[height]
if !ok || now.Sub(pendingTime) <= 0 {
return fmt.Errorf("clock error: block %d received at %s but requested at %s",
height, pendingTime, now)
}
peer.lastRate = size / now.Sub(pendingTime).Nanoseconds()
sc.setStateAtHeight(height, blockStateReceived)
delete(sc.pendingBlocks, height)
delete(sc.pendingTime, height)
sc.receivedBlocks[height] = peerID
return nil
}
func (sc *scheduler) markPending(peerID p2p.ID, height int64, time time.Time) error {
state := sc.getStateAtHeight(height)
if state != blockStateNew {
return fmt.Errorf("block %d should be in blockStateNew but is %s", height, state)
}
peer, ok := sc.peers[peerID]
if !ok {
return fmt.Errorf("cannot find peer %s", peerID)
}
if peer.state != peerStateReady {
return fmt.Errorf("cannot schedule %d from %s in %s", height, peerID, peer.state)
}
if height > peer.height {
return fmt.Errorf("cannot request height %d from peer %s that is at height %d",
height, peerID, peer.height)
}
if height < peer.base {
return fmt.Errorf("cannot request height %d for peer %s with base %d",
height, peerID, peer.base)
}
sc.setStateAtHeight(height, blockStatePending)
sc.pendingBlocks[height] = peerID
sc.pendingTime[height] = time
return nil
}
func (sc *scheduler) markProcessed(height int64) error {
// It is possible that a peer error or timeout is handled after the processor
// has processed the block but before the scheduler received this event, so
// when pcBlockProcessed event is received, the block had been requested
// again => don't check the block state.
sc.lastAdvance = time.Now()
sc.height = height + 1
delete(sc.pendingBlocks, height)
delete(sc.pendingTime, height)
delete(sc.receivedBlocks, height)
delete(sc.blockStates, height)
sc.addNewBlocks()
return nil
}
func (sc *scheduler) allBlocksProcessed() bool {
if len(sc.peers) == 0 {
return false
}
return sc.height >= sc.maxHeight()
}
// returns max peer height or the last processed block, i.e. sc.height
func (sc *scheduler) maxHeight() int64 {
max := sc.height - 1
for _, peer := range sc.peers {
if peer.state != peerStateReady {
continue
}
if max < peer.height {
max = peer.height
}
}
return max
}
// lowest block in sc.blockStates with state == blockStateNew or -1 if no new blocks
func (sc *scheduler) nextHeightToSchedule() int64 {
var min int64 = math.MaxInt64
for height, state := range sc.blockStates {
if state == blockStateNew && height < min {
min = height
}
}
if min == math.MaxInt64 {
min = -1
}
return min
}
func (sc *scheduler) pendingFrom(peerID p2p.ID) []int64 {
var heights []int64
for height, pendingPeerID := range sc.pendingBlocks {
if pendingPeerID == peerID {
heights = append(heights, height)
}
}
return heights
}
func (sc *scheduler) selectPeer(height int64) (p2p.ID, error) {
peers := sc.getPeersWithHeight(height)
if len(peers) == 0 {
return "", fmt.Errorf("cannot find peer for height %d", height)
}
// create a map from number of pending requests to a list
// of peers having that number of pending requests.
pendingFrom := make(map[int][]p2p.ID)
for _, peerID := range peers {
numPending := len(sc.pendingFrom(peerID))
pendingFrom[numPending] = append(pendingFrom[numPending], peerID)
}
// find the set of peers with minimum number of pending requests.
var minPending int64 = math.MaxInt64
for mp := range pendingFrom {
if int64(mp) < minPending {
minPending = int64(mp)
}
}
sort.Sort(PeerByID(pendingFrom[int(minPending)]))
return pendingFrom[int(minPending)][0], nil
}
// PeerByID is a list of peers sorted by peerID.
type PeerByID []p2p.ID
func (peers PeerByID) Len() int {
return len(peers)
}
func (peers PeerByID) Less(i, j int) bool {
return bytes.Compare([]byte(peers[i]), []byte(peers[j])) == -1
}
func (peers PeerByID) Swap(i, j int) {
peers[i], peers[j] = peers[j], peers[i]
}
// Handlers
// This handler gets the block, performs some validation and then passes it on to the processor.
func (sc *scheduler) handleBlockResponse(event bcBlockResponse) (Event, error) {
err := sc.touchPeer(event.peerID, event.time)
if err != nil {
// peer does not exist OR not ready
return noOp, nil
}
err = sc.markReceived(event.peerID, event.block.Height, event.size, event.time)
if err != nil {
sc.removePeer(event.peerID)
return scPeerError{peerID: event.peerID, reason: err}, nil
}
return scBlockReceived{peerID: event.peerID, block: event.block}, nil
}
func (sc *scheduler) handleNoBlockResponse(event bcNoBlockResponse) (Event, error) {
// No such peer or peer was removed.
peer, ok := sc.peers[event.peerID]
if !ok || peer.state == peerStateRemoved {
return noOp, nil
}
// The peer may have been just removed due to errors, low speed or timeouts.
sc.removePeer(event.peerID)
return scPeerError{peerID: event.peerID,
reason: fmt.Errorf("peer %v with base %d height %d claims no block for %d",
event.peerID, peer.base, peer.height, event.height)}, nil
}
func (sc *scheduler) handleBlockProcessed(event pcBlockProcessed) (Event, error) {
if event.height != sc.height {
panic(fmt.Sprintf("processed height %d, but expected height %d", event.height, sc.height))
}
err := sc.markProcessed(event.height)
if err != nil {
return scSchedulerFail{reason: err}, nil
}
if sc.allBlocksProcessed() {
return scFinishedEv{reason: "processed all blocks"}, nil
}
return noOp, nil
}
// Handles an error from the processor. The processor had already cleaned the blocks from
// the peers included in this event. Just attempt to remove the peers.
func (sc *scheduler) handleBlockProcessError(event pcBlockVerificationFailure) (Event, error) {
// The peers may have been just removed due to errors, low speed or timeouts.
sc.removePeer(event.firstPeerID)
if event.firstPeerID != event.secondPeerID {
sc.removePeer(event.secondPeerID)
}
if sc.allBlocksProcessed() {
return scFinishedEv{reason: "error on last block"}, nil
}
return noOp, nil
}
func (sc *scheduler) handleAddNewPeer(event bcAddNewPeer) (Event, error) {
sc.ensurePeer(event.peerID)
return noOp, nil
}
func (sc *scheduler) handleRemovePeer(event bcRemovePeer) (Event, error) {
sc.removePeer(event.peerID)
if sc.allBlocksProcessed() {
return scFinishedEv{reason: "removed peer"}, nil
}
// Return scPeerError so the peer (and all associated blocks) is removed from
// the processor.
return scPeerError{peerID: event.peerID, reason: errors.New("peer was stopped")}, nil
}
func (sc *scheduler) handleTryPrunePeer(event rTryPrunePeer) (Event, error) {
// Check behavior of peer responsible to deliver block at sc.height.
timeHeightAsked, ok := sc.pendingTime[sc.height]
if ok && time.Since(timeHeightAsked) > sc.peerTimeout {
// A request was sent to a peer for block at sc.height but a response was not received
// from that peer within sc.peerTimeout. Remove the peer. This is to ensure that a peer
// will be timed out even if it sends blocks at higher heights but prevents progress by
// not sending the block at current height.
sc.removePeer(sc.pendingBlocks[sc.height])
}
prunablePeers := sc.prunablePeers(sc.peerTimeout, sc.minRecvRate, event.time)
if len(prunablePeers) == 0 {
return noOp, nil
}
for _, peerID := range prunablePeers {
sc.removePeer(peerID)
}
// If all blocks are processed we should finish.
if sc.allBlocksProcessed() {
return scFinishedEv{reason: "after try prune"}, nil
}
return scPeersPruned{peers: prunablePeers}, nil
}
func (sc *scheduler) handleResetState(event bcResetState) (Event, error) {
initHeight := event.state.LastBlockHeight + 1
if initHeight == 1 {
initHeight = event.state.InitialHeight
}
sc.initHeight = initHeight
sc.height = initHeight
sc.lastAdvance = time.Now()
sc.addNewBlocks()
return noOp, nil
}
func (sc *scheduler) handleTrySchedule(event rTrySchedule) (Event, error) {
if time.Since(sc.lastAdvance) > sc.syncTimeout {
return scFinishedEv{reason: "timeout, no advance"}, nil
}
nextHeight := sc.nextHeightToSchedule()
if nextHeight == -1 {
return noOp, nil
}
bestPeerID, err := sc.selectPeer(nextHeight)
if err != nil {
return scSchedulerFail{reason: err}, nil
}
if err := sc.markPending(bestPeerID, nextHeight, event.time); err != nil {
return scSchedulerFail{reason: err}, nil // XXX: peerError might be more appropriate
}
return scBlockRequest{peerID: bestPeerID, height: nextHeight}, nil
}
func (sc *scheduler) handleStatusResponse(event bcStatusResponse) (Event, error) {
err := sc.setPeerRange(event.peerID, event.base, event.height)
if err != nil {
return scPeerError{peerID: event.peerID, reason: err}, nil
}
return noOp, nil
}
func (sc *scheduler) handle(event Event) (Event, error) {
switch event := event.(type) {
case bcResetState:
nextEvent, err := sc.handleResetState(event)
return nextEvent, err
case bcStatusResponse:
nextEvent, err := sc.handleStatusResponse(event)
return nextEvent, err
case bcBlockResponse:
nextEvent, err := sc.handleBlockResponse(event)
return nextEvent, err
case bcNoBlockResponse:
nextEvent, err := sc.handleNoBlockResponse(event)
return nextEvent, err
case rTrySchedule:
nextEvent, err := sc.handleTrySchedule(event)
return nextEvent, err
case bcAddNewPeer:
nextEvent, err := sc.handleAddNewPeer(event)
return nextEvent, err
case bcRemovePeer:
nextEvent, err := sc.handleRemovePeer(event)
return nextEvent, err
case rTryPrunePeer:
nextEvent, err := sc.handleTryPrunePeer(event)
return nextEvent, err
case pcBlockProcessed:
nextEvent, err := sc.handleBlockProcessed(event)
return nextEvent, err
case pcBlockVerificationFailure:
nextEvent, err := sc.handleBlockProcessError(event)
return nextEvent, err
default:
return scSchedulerFail{reason: fmt.Errorf("unknown event %v", event)}, nil
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,65 +0,0 @@
package v2
import (
"github.com/Workiva/go-datastructures/queue"
)
// Event is the type that can be added to the priority queue.
type Event queue.Item
type priority interface {
Compare(other queue.Item) int
Priority() int
}
type priorityLow struct{}
type priorityNormal struct{}
type priorityHigh struct{}
func (p priorityLow) Priority() int {
return 1
}
func (p priorityNormal) Priority() int {
return 2
}
func (p priorityHigh) Priority() int {
return 3
}
func (p priorityLow) Compare(other queue.Item) int {
op := other.(priority)
if p.Priority() > op.Priority() {
return 1
} else if p.Priority() == op.Priority() {
return 0
}
return -1
}
func (p priorityNormal) Compare(other queue.Item) int {
op := other.(priority)
if p.Priority() > op.Priority() {
return 1
} else if p.Priority() == op.Priority() {
return 0
}
return -1
}
func (p priorityHigh) Compare(other queue.Item) int {
op := other.(priority)
if p.Priority() > op.Priority() {
return 1
} else if p.Priority() == op.Priority() {
return 0
}
return -1
}
type noOpEvent struct {
priorityLow
}
var noOp = noOpEvent{}

View File

@@ -1,12 +1,12 @@
package blockchain
package blocksync
import (
"errors"
"fmt"
"github.com/gogo/protobuf/proto"
"github.com/cosmos/gogoproto/proto"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blocksync"
"github.com/tendermint/tendermint/types"
)

View File

@@ -1,15 +1,16 @@
package blockchain
package blocksync_test
import (
"encoding/hex"
"math"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain"
"github.com/tendermint/tendermint/blocksync"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blocksync"
"github.com/tendermint/tendermint/types"
)
@@ -28,7 +29,7 @@ func TestBcBlockRequestMessageValidateBasic(t *testing.T) {
tc := tc
t.Run(tc.testName, func(t *testing.T) {
request := bcproto.BlockRequest{Height: tc.requestHeight}
assert.Equal(t, tc.expectErr, ValidateMsg(&request) != nil, "Validate Basic had an unexpected result")
assert.Equal(t, tc.expectErr, blocksync.ValidateMsg(&request) != nil, "Validate Basic had an unexpected result")
})
}
}
@@ -48,14 +49,14 @@ func TestBcNoBlockResponseMessageValidateBasic(t *testing.T) {
tc := tc
t.Run(tc.testName, func(t *testing.T) {
nonResponse := bcproto.NoBlockResponse{Height: tc.nonResponseHeight}
assert.Equal(t, tc.expectErr, ValidateMsg(&nonResponse) != nil, "Validate Basic had an unexpected result")
assert.Equal(t, tc.expectErr, blocksync.ValidateMsg(&nonResponse) != nil, "Validate Basic had an unexpected result")
})
}
}
func TestBcStatusRequestMessageValidateBasic(t *testing.T) {
request := bcproto.StatusRequest{}
assert.NoError(t, ValidateMsg(&request))
assert.NoError(t, blocksync.ValidateMsg(&request))
}
func TestBcStatusResponseMessageValidateBasic(t *testing.T) {
@@ -73,12 +74,12 @@ func TestBcStatusResponseMessageValidateBasic(t *testing.T) {
tc := tc
t.Run(tc.testName, func(t *testing.T) {
response := bcproto.StatusResponse{Height: tc.responseHeight}
assert.Equal(t, tc.expectErr, ValidateMsg(&response) != nil, "Validate Basic had an unexpected result")
assert.Equal(t, tc.expectErr, blocksync.ValidateMsg(&response) != nil, "Validate Basic had an unexpected result")
})
}
}
// nolint:lll // ignore line length in tests
//nolint:lll // ignore line length in tests
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

View File

@@ -1,4 +1,4 @@
package v0
package blocksync
import (
"errors"
@@ -58,7 +58,7 @@ var peerTimeout = 15 * time.Second // not const so we can override with tests
are not at peer limits, we can probably switch to consensus reactor
*/
// BlockPool keeps track of the fast sync peers, block requests and block responses.
// BlockPool keeps track of the block sync peers, block requests and block responses.
type BlockPool struct {
service.BaseService
startTime time.Time
@@ -410,6 +410,7 @@ func (pool *BlockPool) sendError(err error, peerID p2p.ID) {
}
// for debugging purposes
//
//nolint:unused
func (pool *BlockPool) debug() string {
pool.mtx.Lock()

View File

@@ -1,4 +1,4 @@
package v0
package blocksync
import (
"fmt"

View File

@@ -1,22 +1,21 @@
package v0
package blocksync
import (
"fmt"
"reflect"
"time"
bc "github.com/tendermint/tendermint/blockchain"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain"
bcproto "github.com/tendermint/tendermint/proto/tendermint/blocksync"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
)
const (
// BlockchainChannel is a channel for blocks and status updates (`BlockStore` height)
BlockchainChannel = byte(0x40)
// BlocksyncChannel is a channel for blocks and status updates (`BlockStore` height)
BlocksyncChannel = byte(0x40)
trySyncIntervalMS = 10
@@ -31,7 +30,7 @@ const (
)
type consensusReactor interface {
// for when we switch from blockchain reactor and fast sync to
// for when we switch from blockchain reactor and block sync to
// the consensus machine
SwitchToConsensus(state sm.State, skipWAL bool)
}
@@ -45,8 +44,8 @@ func (e peerError) Error() string {
return fmt.Sprintf("error with peer %v: %s", e.peerID, e.err.Error())
}
// BlockchainReactor handles long-term catchup syncing.
type BlockchainReactor struct {
// Reactor handles long-term catchup syncing.
type Reactor struct {
p2p.BaseReactor
// immutable
@@ -55,15 +54,15 @@ type BlockchainReactor struct {
blockExec *sm.BlockExecutor
store *store.BlockStore
pool *BlockPool
fastSync bool
blockSync bool
requestsCh <-chan BlockRequest
errorsCh <-chan peerError
}
// NewBlockchainReactor returns new reactor instance.
func NewBlockchainReactor(state sm.State, blockExec *sm.BlockExecutor, store *store.BlockStore,
fastSync bool) *BlockchainReactor {
// NewReactor returns new reactor instance.
func NewReactor(state sm.State, blockExec *sm.BlockExecutor, store *store.BlockStore,
blockSync bool) *Reactor {
if state.LastBlockHeight != store.Height() {
panic(fmt.Sprintf("state (%v) and store (%v) height mismatch", state.LastBlockHeight,
@@ -81,28 +80,28 @@ func NewBlockchainReactor(state sm.State, blockExec *sm.BlockExecutor, store *st
}
pool := NewBlockPool(startHeight, requestsCh, errorsCh)
bcR := &BlockchainReactor{
bcR := &Reactor{
initialState: state,
blockExec: blockExec,
store: store,
pool: pool,
fastSync: fastSync,
blockSync: blockSync,
requestsCh: requestsCh,
errorsCh: errorsCh,
}
bcR.BaseReactor = *p2p.NewBaseReactor("BlockchainReactor", bcR)
bcR.BaseReactor = *p2p.NewBaseReactor("Reactor", bcR)
return bcR
}
// SetLogger implements service.Service by setting the logger on reactor and pool.
func (bcR *BlockchainReactor) SetLogger(l log.Logger) {
func (bcR *Reactor) SetLogger(l log.Logger) {
bcR.BaseService.Logger = l
bcR.pool.Logger = l
}
// OnStart implements service.Service.
func (bcR *BlockchainReactor) OnStart() error {
if bcR.fastSync {
func (bcR *Reactor) OnStart() error {
if bcR.blockSync {
err := bcR.pool.Start()
if err != nil {
return err
@@ -112,9 +111,9 @@ func (bcR *BlockchainReactor) OnStart() error {
return nil
}
// SwitchToFastSync is called by the state sync reactor when switching to fast sync.
func (bcR *BlockchainReactor) SwitchToFastSync(state sm.State) error {
bcR.fastSync = true
// SwitchToBlockSync is called by the state sync reactor when switching to block sync.
func (bcR *Reactor) SwitchToBlockSync(state sm.State) error {
bcR.blockSync = true
bcR.initialState = state
bcR.pool.height = state.LastBlockHeight + 1
@@ -127,8 +126,8 @@ func (bcR *BlockchainReactor) SwitchToFastSync(state sm.State) error {
}
// OnStop implements service.Service.
func (bcR *BlockchainReactor) OnStop() {
if bcR.fastSync {
func (bcR *Reactor) OnStop() {
if bcR.blockSync {
if err := bcR.pool.Stop(); err != nil {
bcR.Logger.Error("Error stopping pool", "err", err)
}
@@ -136,21 +135,21 @@ func (bcR *BlockchainReactor) OnStop() {
}
// GetChannels implements Reactor
func (bcR *BlockchainReactor) GetChannels() []*p2p.ChannelDescriptor {
func (bcR *Reactor) GetChannels() []*p2p.ChannelDescriptor {
return []*p2p.ChannelDescriptor{
{
ID: BlockchainChannel,
ID: BlocksyncChannel,
Priority: 5,
SendQueueCapacity: 1000,
RecvBufferCapacity: 50 * 4096,
RecvMessageCapacity: bc.MaxMsgSize,
RecvMessageCapacity: MaxMsgSize,
},
}
}
// AddPeer implements Reactor by sending our state to peer.
func (bcR *BlockchainReactor) AddPeer(peer p2p.Peer) {
msgBytes, err := bc.EncodeMsg(&bcproto.StatusResponse{
func (bcR *Reactor) AddPeer(peer p2p.Peer) {
msgBytes, err := EncodeMsg(&bcproto.StatusResponse{
Base: bcR.store.Base(),
Height: bcR.store.Height()})
if err != nil {
@@ -158,7 +157,7 @@ func (bcR *BlockchainReactor) AddPeer(peer p2p.Peer) {
return
}
peer.Send(BlockchainChannel, msgBytes)
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
@@ -166,13 +165,13 @@ func (bcR *BlockchainReactor) AddPeer(peer p2p.Peer) {
}
// RemovePeer implements Reactor by removing peer from the pool.
func (bcR *BlockchainReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
func (bcR *Reactor) RemovePeer(peer p2p.Peer, reason interface{}) {
bcR.pool.RemovePeer(peer.ID())
}
// respondToPeer loads a block and sends it to the requesting peer,
// if we have it. Otherwise, we'll respond saying we don't have it.
func (bcR *BlockchainReactor) respondToPeer(msg *bcproto.BlockRequest,
func (bcR *Reactor) respondToPeer(msg *bcproto.BlockRequest,
src p2p.Peer) (queued bool) {
block := bcR.store.LoadBlock(msg.Height)
@@ -183,36 +182,36 @@ func (bcR *BlockchainReactor) respondToPeer(msg *bcproto.BlockRequest,
return false
}
msgBytes, err := bc.EncodeMsg(&bcproto.BlockResponse{Block: bl})
msgBytes, err := EncodeMsg(&bcproto.BlockResponse{Block: bl})
if err != nil {
bcR.Logger.Error("could not marshal msg", "err", err)
return false
}
return src.TrySend(BlockchainChannel, msgBytes)
return src.TrySend(BlocksyncChannel, msgBytes)
}
bcR.Logger.Info("Peer asking for a block we don't have", "src", src, "height", msg.Height)
msgBytes, err := bc.EncodeMsg(&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(BlockchainChannel, msgBytes)
return src.TrySend(BlocksyncChannel, msgBytes)
}
// Receive implements Reactor by handling 4 types of messages (look below).
func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
msg, err := bc.DecodeMsg(msgBytes)
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", src, "chId", chID, "err", err)
bcR.Switch.StopPeerForError(src, err)
return
}
if err = bc.ValidateMsg(msg); err != nil {
if err = ValidateMsg(msg); err != nil {
bcR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
bcR.Switch.StopPeerForError(src, err)
return
@@ -232,7 +231,7 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
bcR.pool.AddBlock(src.ID(), bi, len(msgBytes))
case *bcproto.StatusRequest:
// Send peer our state.
msgBytes, err := bc.EncodeMsg(&bcproto.StatusResponse{
msgBytes, err := EncodeMsg(&bcproto.StatusResponse{
Height: bcR.store.Height(),
Base: bcR.store.Base(),
})
@@ -240,7 +239,7 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
bcR.Logger.Error("could not convert msg to protobut", "err", err)
return
}
src.TrySend(BlockchainChannel, msgBytes)
src.TrySend(BlocksyncChannel, msgBytes)
case *bcproto.StatusResponse:
// Got a peer status. Unverified.
bcR.pool.SetPeerRange(src.ID(), msg.Base, msg.Height)
@@ -253,7 +252,7 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
// Handle messages from the poolReactor telling the reactor what to do.
// NOTE: Don't sleep in the FOR_LOOP or otherwise slow it down!
func (bcR *BlockchainReactor) poolRoutine(stateSynced bool) {
func (bcR *Reactor) poolRoutine(stateSynced bool) {
trySyncTicker := time.NewTicker(trySyncIntervalMS * time.Millisecond)
defer trySyncTicker.Stop()
@@ -286,13 +285,13 @@ func (bcR *BlockchainReactor) poolRoutine(stateSynced bool) {
if peer == nil {
continue
}
msgBytes, err := bc.EncodeMsg(&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(BlockchainChannel, msgBytes)
queued := peer.TrySend(BlocksyncChannel, msgBytes)
if !queued {
bcR.Logger.Debug("Send queue is full, drop block request", "peer", peer.ID(), "height", request.Height)
}
@@ -304,7 +303,7 @@ func (bcR *BlockchainReactor) poolRoutine(stateSynced bool) {
case <-statusUpdateTicker.C:
// ask for status updates
go bcR.BroadcastStatusRequest() // nolint: errcheck
go bcR.BroadcastStatusRequest() //nolint: errcheck
}
}
@@ -388,14 +387,14 @@ FOR_LOOP:
if peer != nil {
// NOTE: we've already removed the peer's request, but we
// still need to clean up the rest.
bcR.Switch.StopPeerForError(peer, fmt.Errorf("blockchainReactor validation error: %v", err))
bcR.Switch.StopPeerForError(peer, fmt.Errorf("Reactor validation error: %v", err))
}
peerID2 := bcR.pool.RedoRequest(second.Height)
peer2 := bcR.Switch.Peers().Get(peerID2)
if peer2 != nil && peer2 != peer {
// NOTE: we've already removed the peer's request, but we
// still need to clean up the rest.
bcR.Switch.StopPeerForError(peer2, fmt.Errorf("blockchainReactor validation error: %v", err))
bcR.Switch.StopPeerForError(peer2, fmt.Errorf("Reactor validation error: %v", err))
}
continue FOR_LOOP
}
@@ -407,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))
@@ -416,7 +415,7 @@ FOR_LOOP:
if blocksSynced%100 == 0 {
lastRate = 0.9*lastRate + 0.1*(100/time.Since(lastHundred).Seconds())
bcR.Logger.Info("Fast Sync Rate", "height", bcR.pool.height,
bcR.Logger.Info("Block Sync Rate", "height", bcR.pool.height,
"max_peer_height", bcR.pool.MaxPeerHeight(), "blocks/s", lastRate)
lastHundred = time.Now()
}
@@ -430,14 +429,14 @@ FOR_LOOP:
}
// BroadcastStatusRequest broadcasts `BlockStore` base and height.
func (bcR *BlockchainReactor) BroadcastStatusRequest() error {
bm, err := bc.EncodeMsg(&bcproto.StatusRequest{})
func (bcR *Reactor) BroadcastStatusRequest() error {
bm, err := EncodeMsg(&bcproto.StatusRequest{})
if err != nil {
bcR.Logger.Error("could not convert msg to proto", "err", err)
return fmt.Errorf("could not convert msg to proto: %w", err)
}
bcR.Switch.Broadcast(BlockchainChannel, bm)
bcR.Switch.Broadcast(BlocksyncChannel, bm)
return nil
}

View File

@@ -1,4 +1,4 @@
package v0
package blocksync
import (
"fmt"
@@ -15,12 +15,12 @@ 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"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
sf "github.com/tendermint/tendermint/state/test/factory"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
@@ -43,29 +43,29 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
return &types.GenesisDoc{
GenesisTime: tmtime.Now(),
ChainID: config.ChainID(),
ChainID: test.DefaultTestChainID,
Validators: validators,
}, privValidators
}
type BlockchainReactorPair struct {
reactor *BlockchainReactor
type ReactorPair struct {
reactor *Reactor
app proxy.AppConns
}
func newBlockchainReactor(
func newReactor(
t *testing.T,
logger log.Logger,
genDoc *types.GenesisDoc,
privVals []types.PrivValidator,
maxBlockHeight int64) BlockchainReactorPair {
maxBlockHeight int64) ReactorPair {
if len(privVals) != 1 {
panic("only support one validator")
}
app := &testApp{}
cc := proxy.NewLocalClientCreator(app)
proxyApp := proxy.NewAppConns(cc)
proxyApp := proxy.NewAppConns(cc, proxy.NopMetrics())
err := proxyApp.Start()
if err != nil {
panic(fmt.Errorf("error start app: %w", err))
@@ -73,7 +73,9 @@ func newBlockchainReactor(
blockDB := dbm.NewMemDB()
stateDB := dbm.NewMemDB()
stateStore := sm.NewStore(stateDB)
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
DiscardABCIResponses: false,
})
blockStore := store.NewBlockStore(blockDB)
state, err := stateStore.LoadFromDBOrGenesisDoc(genDoc)
@@ -93,14 +95,16 @@ func newBlockchainReactor(
mock.Anything,
mock.Anything).Return(nil)
// Make the BlockchainReactor itself.
// Make the Reactor itself.
// NOTE we have to create and commit the blocks first because
// pool.height is determined from the store.
fastSync := true
db := dbm.NewMemDB()
stateStore = sm.NewStore(db)
stateStore = sm.NewStore(db, sm.StoreOptions{
DiscardABCIResponses: false,
})
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
mp, sm.EmptyEvidencePool{})
mp, sm.EmptyEvidencePool{}, blockStore)
if err = stateStore.Save(state); err != nil {
panic(err)
}
@@ -127,13 +131,13 @@ func newBlockchainReactor(
lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()})
}
thisBlock := sf.MakeBlock(state, blockHeight, lastCommit)
thisBlock := state.MakeBlock(blockHeight, nil, lastCommit, nil, state.Validators.Proposer.Address)
thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes)
require.NoError(t, err)
blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()}
state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock)
state, err = blockExec.ApplyBlock(state, blockID, thisBlock)
if err != nil {
panic(fmt.Errorf("error apply block: %w", err))
}
@@ -141,23 +145,23 @@ func newBlockchainReactor(
blockStore.SaveBlock(thisBlock, thisParts, lastCommit)
}
bcReactor := NewBlockchainReactor(state.Copy(), blockExec, blockStore, fastSync)
bcReactor := NewReactor(state.Copy(), blockExec, blockStore, fastSync)
bcReactor.SetLogger(logger.With("module", "blockchain"))
return BlockchainReactorPair{bcReactor, proxyApp}
return ReactorPair{bcReactor, proxyApp}
}
func TestNoBlockResponse(t *testing.T) {
config = cfg.ResetTestRoot("blockchain_reactor_test")
config = test.ResetTestRoot("blockchain_reactor_test")
defer os.RemoveAll(config.RootDir)
genDoc, privVals := randGenesisDoc(1, false, 30)
maxBlockHeight := int64(65)
reactorPairs := make([]BlockchainReactorPair, 2)
reactorPairs := make([]ReactorPair, 2)
reactorPairs[0] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight)
reactorPairs[1] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0)
reactorPairs[0] = newReactor(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight)
reactorPairs[1] = newReactor(t, log.TestingLogger(), genDoc, privVals, 0)
p2p.MakeConnectedSwitches(config.P2P, 2, func(i int, s *p2p.Switch) *p2p.Switch {
s.AddReactor("BLOCKCHAIN", reactorPairs[i].reactor)
@@ -210,7 +214,7 @@ func TestNoBlockResponse(t *testing.T) {
// Alternatively we could actually dial a TCP conn but
// that seems extreme.
func TestBadBlockStopsPeer(t *testing.T) {
config = cfg.ResetTestRoot("blockchain_reactor_test")
config = test.ResetTestRoot("blockchain_reactor_test")
defer os.RemoveAll(config.RootDir)
genDoc, privVals := randGenesisDoc(1, false, 30)
@@ -218,7 +222,7 @@ func TestBadBlockStopsPeer(t *testing.T) {
// Other chain needs a different validator set
otherGenDoc, otherPrivVals := randGenesisDoc(1, false, 30)
otherChain := newBlockchainReactor(t, log.TestingLogger(), otherGenDoc, otherPrivVals, maxBlockHeight)
otherChain := newReactor(t, log.TestingLogger(), otherGenDoc, otherPrivVals, maxBlockHeight)
defer func() {
err := otherChain.reactor.Stop()
@@ -227,12 +231,12 @@ func TestBadBlockStopsPeer(t *testing.T) {
require.NoError(t, err)
}()
reactorPairs := make([]BlockchainReactorPair, 4)
reactorPairs := make([]ReactorPair, 4)
reactorPairs[0] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight)
reactorPairs[1] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0)
reactorPairs[2] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0)
reactorPairs[3] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0)
reactorPairs[0] = newReactor(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight)
reactorPairs[1] = newReactor(t, log.TestingLogger(), genDoc, privVals, 0)
reactorPairs[2] = newReactor(t, log.TestingLogger(), genDoc, privVals, 0)
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("BLOCKCHAIN", reactorPairs[i].reactor)
@@ -270,7 +274,7 @@ func TestBadBlockStopsPeer(t *testing.T) {
// race, but can't be easily avoided.
reactorPairs[3].reactor.store = otherChain.reactor.store
lastReactorPair := newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0)
lastReactorPair := newReactor(t, log.TestingLogger(), genDoc, privVals, 0)
reactorPairs = append(reactorPairs, lastReactorPair)
switches = append(switches, p2p.MakeConnectedSwitches(config.P2P, 1, func(i int, s *p2p.Switch) *p2p.Switch {

View File

@@ -3,7 +3,7 @@ plugins:
- name: gogofaster
out: ./proto/
opt:
- Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types
- Mgoogle/protobuf/timestamp.proto=github.com/cosmos/gogoproto/types
- Mgoogle/protobuf/duration.proto=github.com/golang/protobuf/ptypes/duration
- plugins=grpc
- paths=source_relative

View File

@@ -1,7 +1,6 @@
build:
roots:
- proto
- third_party/proto
lint:
use:
- BASIC

Some files were not shown because too many files have changed in this diff Show More