Compare commits

...

83 Commits

Author SHA1 Message Date
Marko
53a9ba3233 docs: vuepress version update (#5949)
* vuepress refesh

* bump package-lock.json

Co-authored-by: Cyrus Goh <hello@lovincyrus.com>
2021-01-22 19:23:48 +00:00
Anton Kaliaev
be85434876 evidence: omit bytes field (#5745)
Follow-up to https://github.com/tendermint/tendermint/pull/5743
2020-12-10 22:13:25 +01:00
Tess Rinearson
6a07d08f49 reactors: omit incoming message bytes from reactor logs (#5743)
After a reactor has failed to parse an incoming message, it shouldn't output the "bad" data into the logs, as that data is unfiltered and could have anything in it. (We also don't think this information is helpful to have in the logs anyways.)
2020-12-10 22:13:25 +01:00
Anton Kaliaev
f5b25e020b blockchain/v1: fix deadlock (#5711)
I introduced a new variable - syncEnded, which is now used to prevent
sending new events to channels (which would block otherwise) if reactor
is finished syncing

Closes #4591
2020-12-10 16:05:36 +04:00
Anton Kaliaev
bf873365e7 blockchain/v1: handle peers without blocks (#5701)
Closes #5444

Now we record the fact that a peer does not have a requested block and later use this information to make a new request for the same block from another peer.
2020-12-10 16:05:36 +04:00
Marko
925b2948f0 blockchain/v1: add noBlockResponse handling (#5401)
Add simple `NoBlockResponse` handling to blockchain reactor v1. I tested before and after with erik's e2e testing and was not able to reproduce the inability to sync after the changes were applied

Closes: #5394
2020-12-10 16:05:36 +04:00
Marko
5359e9fed3 backport ci migration (#5758)
backport ci migration from circle to github actions
2020-12-09 15:59:57 +01:00
Anton Kaliaev
37010ad5b2 use fmt.Sprint for string to int conversion 2020-11-16 16:50:39 +04:00
Anton Kaliaev
a26551985f bump version and update changelog 2020-11-16 16:50:39 +04:00
Anton Kaliaev
f80a1bc42b privval: increase read/write timeout to 5s and calculate ping interval based on it (#5638)
Partially closes #5550
2020-11-16 16:50:39 +04:00
Anton Kaliaev
5ba30e6f55 consensus: only call privValidator.GetPubKey once per block (#5143)
Closes #4865
2020-11-16 16:50:39 +04:00
Joe Bowman
61ab6718e9 only retrieve pubkey once for all validators (partially fixes #4865) (#4895)
in consensus/state.go, when calulating metrics, retrieve address (ergo, pubkey) once prior to iterating over validatorset to ensure we do not make excessive calls to signer.

Partially closes: #4865
2020-11-16 16:50:39 +04:00
Marko Baricevic
8706d45f3d add dates to changelog 2020-08-05 12:03:28 +02:00
Anton Kaliaev
eebf6f353d bump version 2020-08-05 12:03:28 +02:00
Anton Kaliaev
f9e3092feb add changelog 2020-08-05 12:03:28 +02:00
Anton Kaliaev
9da308fd2a privval: if remote signer errors, don't retry
Refs #5112
2020-08-05 12:03:28 +02:00
Erik Grinaker
f11eae0761 test: revert Go 1.13→1.14 bump
Since we support 1.13 and above, let's use that as a baseline for tests.
2020-05-19 17:27:50 +02:00
Erik Grinaker
7e2870af49 test: fix p2p test build breakage caused by Debian testing
Debian testing caused Docker image build failures:

```
The following packages have unmet dependencies:
 
 libc6-dev : Breaks: libgcc-8-dev (< 8.4.0-2~) but 8.3.0-6 is to be installed
 
E: Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.
```

It does not appear that we actually need testing, so removing it.
2020-05-19 17:27:50 +02:00
Tess Rinearson
f132310a4d release/v0.32.12 2020-05-19 17:27:50 +02:00
Anton Kaliaev
a0af03c3e2 p2p: return masked IP (not the actual IP) in addrbook#groupKey
Closes #4846
Spec https://github.com/tendermint/spec/pull/96
2020-05-19 17:27:50 +02:00
Anton Kaliaev
d85e2e52d2 Release/v0.32.11 (#4709)
* privval: retry GetPubKey, SignVote/Proposal indefinitely

Fixes #4275
2020-04-29 17:25:27 +02:00
Alessio Treglia
eab4d6d82b Merge pull request from GHSA-v24h-pjjv-mcp6
v0.32.10: advisory fix
2020-04-09 15:48:13 +02:00
Anton Kaliaev
cf114c98d4 UnconditionalPeerIDs do not exist in v0.32 2020-04-06 11:25:24 +04:00
Anton Kaliaev
49d8c0b174 changelog: fix grammar 2020-04-03 17:31:01 +04:00
Anton Kaliaev
63c9384c8c update changelog and version 2020-04-03 17:18:49 +04:00
Anton Kaliaev
0a1ef4aa0f p2p: limit the number of incoming connections
to p2p.max_num_inbound_peers + len(p2p.unconditional_peer_ids)
2020-04-03 17:17:51 +04:00
Tess Rinearson
ffb0278d95 mempool: reserve IDs in InitPeer instead of AddPeer 2020-04-03 17:17:36 +04:00
Marko
e6a7757bb4 release: changelog & version (#4298)
* release: changelog & version

- update version and changelogs

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

* change changelog pending version
2020-01-10 12:30:56 -08:00
Marko
51ccaf6fb8 metrics: add metrics for specific validators (#4294)
* add metrics

* change == to !=

* update metrics

* cs: check cs.privValidator is not nil in recordMetrics

Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
2020-01-10 12:30:56 -08:00
Greg Szabo
be771f225a rpc/lib: RPC client basic authentication with URL parsing refactored (#4285)
Enable basic authentication in the RPC client using the https://username:password@node:port format.

Issue #4248 has details about what was refactored/enhanced (it's not as bad as it looks.)

I'm open to suggestions on where/how the documentation should be updated.

Please note that PR #4284 is superseded with this PR. The reason for this is because both PR makes changes to the same code.
2020-01-10 12:30:56 -08:00
Greg Szabo
aad59f2a9a rpc/lib: fix RPC client, which was previously resolving https protocol to http (#4131) (#4284)
Fixes #4051

Function `parseRemoteAddr` is forcing protocol HTTP and protocol HTTPs to tcp. This causes the bug in the issue #4051.

I find that the tcp is only needed where `net.Dial`. So I moved the switch to makeHTTPDialer.

This is a backport to the v0.32 branch.

Co-authored-by: yk <tankhoon@gmail.com>
Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
2020-01-10 12:30:56 -08:00
Greg Szabo
d494952c82 cs: don't panic when block is not found in store (#4163) (#4287)
Fixes #4069

Backport for v0.32.9 cherry-picked from master at ee6601a.

Co-authored-by: Greg Zaitsev <greg.zaitsev@gmail.com>
2020-01-10 12:30:56 -08:00
Tess Rinearson
14e04f7606 Merge pull request #4161 from tendermint/release/v0.32.8
Release/v0.32.8
2019-11-19 15:03:24 +01:00
Tess Rinearson
83f1801625 Merge remote-tracking branch 'origin/v0.32' into release/v0.32.8 2019-11-19 14:47:49 +01:00
Marko
95530285d9 rc2/v0.32.8 (#4101)
This commit contains commit messages from the 52 commits from Tendermint 0.32.0 to 0.32.7. This is a result of creating releases from our security advisories, rather than merging these advisories back into the main repo before creating releases. In the future, we will adopt a git workflow that will reduce these commits to only the commits that make up RC2 for (for example) Tendermint 0.32.8.

* docs: fix consensus spec formatting (#3804)

* abci/server: recover from app panics in socket server (#3809)

fixes #3800

* abci/client: fix DATA RACE in gRPC client (#3798)

* Remove go func {}()

closes #357

- Remove go func(){}() that caused race condiditon

- To reproduce
	- add -race in make file to `install_abci`
	- Remove `CGO_ENABLED=0` & add -race to `install`

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

* remove -race

* fix data race

also, reorder callbacks similarly to socket client

* docs: "Writing a built-in Tendermint Core application in Go" guide (#3608)

* docs: go built-in guide

* fix package imports, add badger db, simplify Query

* newTendermint function

* working example

* finish the first guide

* add one more note

* add the second Golang guide - external ABCI app

* fix typos

* libs: Remove db from tendermint in favor of tendermint/tm-cmn (#3811)

* Remove db from tendemrint in favor of tendermint/tm-cmn

- remove db from `libs`
- update dependancy, there have been no breaking changes in the updated deps
	- https://github.com/grpc/grpc-go/releases
	- https://github.com/golang/protobuf/releases

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

* changelog add

* gofmt

* more gofmt

*  docs: add A TOC to the Readme.md of ADR Section (#3820)

* ADR TOC in readme.md

* Added A TOC to the Readme.md of ADR Section

- Added table of contents to the Readme of the architecture section.
	- Easier to traverse and when you know what is there.
	- If the Adr's become viewable online it would help guide the user

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

* add tm-cmn to subprojects

* normalize word

* rpc: make max_body_bytes and max_header_bytes configurable (#3818)

* rpc: make max_body_bytes and max_header_bytes configurable

* update changelog pending

* p2p/conn: Add Bufferpool (#3664)

* use byte buffer pool to decreass allocs

* wrap to put buffer in defer

* wapper defer

* add dependency

* remove Gopkg,*

* add change log

* rpc: /broadcast_evidence (#3481)

* implement broadcast_duplicate_vote endpoint

* fix test_cover

* address comments

* address comments

* Update abci/example/kvstore/persistent_kvstore.go

Co-Authored-By: mossid <torecursedivine@gmail.com>

* Update rpc/client/main_test.go

Co-Authored-By: mossid <torecursedivine@gmail.com>

* address comments in progress

* reformat the code

* make linter happy

* make tests pass

* replace BroadcastDuplicateVote with BroadcastEvidence

* fix test

* fix endpoint name

* improve doc

* fix TestBroadcastEvidenceDuplicateVote

* Update rpc/core/evidence.go

Co-Authored-By: Thane Thomson <connect@thanethomson.com>

* add changelog entry

* fix TestBroadcastEvidenceDuplicateVote

* mempool: make max_msg_bytes configurable (#3826)

* mempool: make max_msg_bytes configurable

* apply suggestions from code review

* update changelog pending

* apply suggestions from code review again

* rpc: return err if page is incorrect (less than 0 or greater than tot… (#3825)

* rpc: return err if page is incorrect (less than 0 or greater than total pages)

Fixes #3813

* fix rpc_test

* blockchain: Reorg reactor (#3561)

* go routines in blockchain reactor

* Added reference to the go routine diagram

* Initial commit

* cleanup

* Undo testing_logger change, committed by mistake

* Fix the test loggers

* pulled some fsm code into pool.go

* added pool tests

* changes to the design

added block requests under peer

moved the request trigger in the reactor poolRoutine, triggered now by a ticker

in general moved everything required for making block requests smarter in the poolRoutine

added a simple map of heights to keep track of what will need to be requested next

added a few more tests

* send errors to FSM in a different channel than blocks

send errors (RemovePeer) from switch on a different channel than the
one receiving blocks
renamed channels
added more pool tests

* more pool tests

* lint errors

* more tests

* more tests

* switch fast sync to new implementation

* fixed data race in tests

* cleanup

* finished fsm tests

* address golangci comments :)

* address golangci comments :)

* Added timeout on next block needed to advance

* updating docs and cleanup

* fix issue in test from previous cleanup

* cleanup

* Added termination scenarios, tests and more cleanup

* small fixes to adr, comments and cleanup

* Fix bug in sendRequest()

If we tried to send a request to a peer not present in the switch, a
missing continue statement caused the request to be blackholed in a peer
that was removed and never retried.

While this bug was manifesting, the reactor kept asking for other
blocks that would be stored and never consumed. Added the number of
unconsumed blocks in the math for requesting blocks ahead of current
processing height so eventually there will be no more blocks requested
until the already received ones are consumed.

* remove bpPeer's didTimeout field

* Use distinct err codes for peer timeout and FSM timeouts

* Don't allow peers to update with lower height

* review comments from Ethan and Zarko

* some cleanup, renaming, comments

* Move block execution in separate goroutine

* Remove pool's numPending

* review comments

* fix lint, remove old blockchain reactor and duplicates in fsm tests

* small reorg around peer after review comments

* add the reactor spec

* verify block only once

* review comments

* change to int for max number of pending requests

* cleanup and godoc

* Add configuration flag fast sync version

* golangci fixes

* fix config template

* move both reactor versions under blockchain

* cleanup, golint, renaming stuff

* updated documentation, fixed more golint warnings

* integrate with behavior package

* sync with master

* gofmt

* add changelog_pending entry

* move to improvments

* suggestion to changelog entry

* Renamed wire.go to codec.go (#3827)

* Renamed wire.go to codec.go

- Wire was the previous name of amino
- Codec describes the file better than `wire` & `amino`

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

* ide error

* rename amino.go to codec.go

* docs: add guides to docs (#3830)

* add staticcheck linting (#3828)

cleanup to add linter

    grpc change:
        https://godoc.org/google.golang.org/grpc#WithContextDialer
        https://godoc.org/google.golang.org/grpc#WithDialer
        grpc/grpc-go#2627
    prometheous change:
        due to UninstrumentedHandler, being deprecated in the future
    empty branch = empty if or else statement
        didn't delete them entirely but commented
        couldn't find a reason to have them
    could not replicate the issue #3406
        but if want to keep it commented then we should comment out the if statement as well

* types: move MakeVote / MakeBlock functions (#3819)

to the types package

Paritally Fixes #3584

* p2p: Fix error logging for connection stop (#3824)

* p2p: fix false-positive error logging when stopping connections

This changeset fixes two types of false-positive errors occurring during
connection shutdown.

The first occurs when the process invokes FlushStop() or Stop() on a
connection. While the previous behavior did properly wait for the sendRoutine
to finish, it did not notify the recvRoutine that the connection was shutting
down. This would cause the recvRouting to receive and error when reading and
log this error. The changeset fixes this by notifying the recvRoutine that
the connection is shutting down.

The second occurs when the connection is terminated (gracefully) by the other side.
The recvRoutine would get an EOF error during the read, log it, and stop the connection
with an error. The changeset detects EOF and gracefully shuts down the connection.

* bring back the comment about flushing

* add changelog entry

* listen for quitRecvRoutine too

* we have to call stopForError

Otherwise peer won't be removed from the peer set and maybe readded
later.

* p2p: Do not write 'Couldn't connect to any seeds' if there are no seeds (#3834)

* Do not write 'Couldn't connect to any seeds' if there are no seeds

* changelog

* remove privValUpgrade

* Fix typo in changelog

* Update CHANGELOG_PENDING.md

Co-Authored-By: Marko <marbar3778@yahoo.com>

I'm setting up all peers dynamically by calling dial_peers, so p2p.seeds in configs is empty, and I'm seeing error log a lot in logs.

* docs: add a footer to guides (#3835)

* docs: "Writing a Tendermint Core application in Kotlin (gRPC)" guide (#3838)

* add abci grpc kotlin guide

* Update docs/guides/kotlin.md

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

* Update docs/guides/kotlin.md

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

* Update docs/guides/kotlin.md

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

* Update kotlin.md

*  node: allow replacing existing p2p.Reactor(s)  (#3846)

* node: allow replacing existing p2p.Reactor(s)

using [`CustomReactors`
option](https://godoc.org/github.com/tendermint/tendermint/node#CustomReactors).
Warning: beware of accidental name clashes. Here is the list of existing
reactors: MEMPOOL, BLOCKCHAIN, CONSENSUS, EVIDENCE, PEX.

* check the absence of "CUSTOM" prefix

* merge 2 tests

* add doc.go to node package

* gocritic (1/2) (#3836)

    Add gocritic as a linter

    The linting is not complete, but should i complete in this PR or in a following.

    23 files have been touched so it may be better to do in a following PR


Commits:

* Add gocritic to linting

- Added gocritic to linting

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

* gocritic

* pr comments

* remove switch in cmdBatch

* tm-cmn to tm-db (#3850)

* tm-cmn to tm-db

* go.mod changes

* go.mod changes

* more go.mod

* fix tm-db

* ci fix, pending change

* version tmdb (#3854)

* txindexer: Refactor Tx Search Aggregation (#3851)

- Replace the previous intersect call, which was called at each query condition, with a map intersection.
- Replace fmt.Sprintf with string()

closes: #3076

Benchmarks

```
Old
goos: darwin
goarch: amd64
pkg: github.com/tendermint/tendermint/state/txindex/kv
BenchmarkTxSearch-4   	     200	 103641206 ns/op	 7998416 B/op	   71171 allocs/op
PASS
ok  	github.com/tendermint/tendermint/state/txindex/kv	26.019s

New
goos: darwin
goarch: amd64
pkg: github.com/tendermint/tendermint/state/txindex/kv
BenchmarkTxSearch-4   	    1000	  38615024 ns/op	13515226 B/op	  166460 allocs/op
PASS
ok  	github.com/tendermint/tendermint/state/txindex/kv	53.618s
```

~62% performance improvement

Commits:

* Refactor tx search

* Add pending changelog entry

* Add tx search benchmarking

* remove intermediate hashes list

also reset timer in BenchmarkTxSearch
and fix other benchmark

* fix import

* Add test cases

* Fix searching

* Replace fmt.Sprintf with string

* Update state/txindex/kv/kv.go

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

* Rename params

* Cleanup

* Check error in benchmarks

* release for v0.32.2

* Merge PR #3860: Update log v0.32.2

* changelog updates

* pr comments

* Fix for panic in signature verification if a peer sends a nil public key.

* update version.go

* Changelog update

* Update CHANGELOG.md

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

* update changelog

* p2p: only allow ed25519 pubkeys when connecting

also, recover from any possible failures in acceptPeers

Refs #4030

* update changelog and bump version to v0.32.6

* set the date to today

* cs: panic only when WAL#WriteSync fails

- modify WAL#Write and WAL#WriteSync to return an error

* types: validate Part#Proof

add ValidateBasic to crypto/merkle/SimpleProof

* cs: limit max bit array size and block parts count

* cs: test new limits

* cs: only assert important stuff

* update changelog and bump version to 0.32.7

* fixes after Ethan's review

* align max wal msg and max consensus msg sizes

* fix tests

* fix test

* Rc2 v0.32.8

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

* move issue to big fix
2019-11-19 13:17:21 +01:00
Anton Kaliaev
7b67ee408b fix test 2019-10-29 11:00:56 -07:00
Anton Kaliaev
7ffd3fff43 fix tests 2019-10-29 11:00:56 -07:00
Anton Kaliaev
c013501f45 align max wal msg and max consensus msg sizes 2019-10-29 11:00:56 -07:00
Anton Kaliaev
7ec2dff6fd fixes after Ethan's review 2019-10-29 11:00:56 -07:00
Anton Kaliaev
b5cad43b26 update changelog and bump version to 0.32.7 2019-10-29 11:00:56 -07:00
Anton Kaliaev
714948505b cs: only assert important stuff 2019-10-29 11:00:56 -07:00
Anton Kaliaev
564d6a203a cs: test new limits 2019-10-29 11:00:56 -07:00
Anton Kaliaev
c38dbdb640 cs: limit max bit array size and block parts count 2019-10-29 11:00:56 -07:00
Anton Kaliaev
c207fa6eff types: validate Part#Proof
add ValidateBasic to crypto/merkle/SimpleProof
2019-10-29 11:00:56 -07:00
Anton Kaliaev
470a23f9b4 cs: panic only when WAL#WriteSync fails
- modify WAL#Write and WAL#WriteSync to return an error
2019-10-29 11:00:56 -07:00
Anton Kaliaev
c4ba93a1e6 set the date to today 2019-10-10 09:01:51 -07:00
Anton Kaliaev
88946fd6d8 update changelog and bump version to v0.32.6 2019-10-10 09:01:51 -07:00
Anton Kaliaev
ab62fd977f p2p: only allow ed25519 pubkeys when connecting
also, recover from any possible failures in acceptPeers

Refs #4030
2019-10-10 09:01:51 -07:00
Anton Kaliaev
0f111b3c5c update changelog 2019-10-01 23:11:51 -07:00
Zaki Manian
b08f655024 Update CHANGELOG.md
Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>
2019-10-01 23:11:51 -07:00
Zaki Manian
d6ea1ed96f Changelog update 2019-10-01 23:11:51 -07:00
Zaki Manian
d06286916d update version.go 2019-10-01 23:11:51 -07:00
Zaki Manian
0354ea87f7 Fix for panic in signature verification if a peer sends a nil public key. 2019-10-01 23:11:51 -07:00
Ethan Buchman
ff2308b5f4 Merge pull request #4002 from tendermint/release/v0.32.4
Release/v0.32.4
2019-09-20 11:17:52 -04:00
Ethan Buchman
0ad70fb69a Merge pull request #3926 from tendermint/anton/v0.32.3
v0.32.3
2019-08-28 09:02:58 -04:00
Anton Kaliaev
86a581f28f Merge branch 'master' into v0.32 2019-08-28 12:43:24 +04:00
Marko
76f3db06b8 Merge PR #3860: Update log v0.32.2
* changelog updates

* pr comments
2019-08-01 10:28:32 -07:00
Marko Baricevic
15878dc80c release for v0.32.2 2019-08-01 10:28:32 -07:00
Alexander Bezobchuk
aacc71dc29 txindexer: Refactor Tx Search Aggregation (#3851)
- Replace the previous intersect call, which was called at each query condition, with a map intersection.
- Replace fmt.Sprintf with string()

closes: #3076

Benchmarks

```
Old
goos: darwin
goarch: amd64
pkg: github.com/tendermint/tendermint/state/txindex/kv
BenchmarkTxSearch-4   	     200	 103641206 ns/op	 7998416 B/op	   71171 allocs/op
PASS
ok  	github.com/tendermint/tendermint/state/txindex/kv	26.019s

New
goos: darwin
goarch: amd64
pkg: github.com/tendermint/tendermint/state/txindex/kv
BenchmarkTxSearch-4   	    1000	  38615024 ns/op	13515226 B/op	  166460 allocs/op
PASS
ok  	github.com/tendermint/tendermint/state/txindex/kv	53.618s
```

~62% performance improvement

Commits:

* Refactor tx search

* Add pending changelog entry

* Add tx search benchmarking

* remove intermediate hashes list

also reset timer in BenchmarkTxSearch
and fix other benchmark

* fix import

* Add test cases

* Fix searching

* Replace fmt.Sprintf with string

* Update state/txindex/kv/kv.go

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

* Rename params

* Cleanup

* Check error in benchmarks
2019-08-01 10:28:32 -07:00
Marko
d56fb6ed22 version tmdb (#3854) 2019-08-01 10:28:32 -07:00
Marko
8025d402e2 tm-cmn to tm-db (#3850)
* tm-cmn to tm-db

* go.mod changes

* go.mod changes

* more go.mod

* fix tm-db

* ci fix, pending change
2019-08-01 10:28:32 -07:00
Marko
513a32a6e3 gocritic (1/2) (#3836)
Add gocritic as a linter

    The linting is not complete, but should i complete in this PR or in a following.

    23 files have been touched so it may be better to do in a following PR


Commits:

* Add gocritic to linting

- Added gocritic to linting

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

* gocritic

* pr comments

* remove switch in cmdBatch
2019-08-01 10:28:32 -07:00
Anton Kaliaev
5c9d6d839e node: allow replacing existing p2p.Reactor(s) (#3846)
* node: allow replacing existing p2p.Reactor(s)

using [`CustomReactors`
option](https://godoc.org/github.com/tendermint/tendermint/node#CustomReactors).
Warning: beware of accidental name clashes. Here is the list of existing
reactors: MEMPOOL, BLOCKCHAIN, CONSENSUS, EVIDENCE, PEX.

* check the absence of "CUSTOM" prefix

* merge 2 tests

* add doc.go to node package
2019-08-01 10:28:32 -07:00
Ivan Kushmantsev
53fdcfd7e9 docs: "Writing a Tendermint Core application in Kotlin (gRPC)" guide (#3838)
* add abci grpc kotlin guide

* Update docs/guides/kotlin.md

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

* Update docs/guides/kotlin.md

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

* Update docs/guides/kotlin.md

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

* Update kotlin.md
2019-08-01 10:28:32 -07:00
Anton Kaliaev
5f6617db7a docs: add a footer to guides (#3835) 2019-08-01 10:28:32 -07:00
folex
6d4f18aa8c p2p: Do not write 'Couldn't connect to any seeds' if there are no seeds (#3834)
* Do not write 'Couldn't connect to any seeds' if there are no seeds

* changelog

* remove privValUpgrade

* Fix typo in changelog

* Update CHANGELOG_PENDING.md

Co-Authored-By: Marko <marbar3778@yahoo.com>

I'm setting up all peers dynamically by calling dial_peers, so p2p.seeds in configs is empty, and I'm seeing error log a lot in logs.
2019-08-01 10:28:32 -07:00
Anton Kaliaev
55066ceaad p2p: Fix error logging for connection stop (#3824)
* p2p: fix false-positive error logging when stopping connections

This changeset fixes two types of false-positive errors occurring during
connection shutdown.

The first occurs when the process invokes FlushStop() or Stop() on a
connection. While the previous behavior did properly wait for the sendRoutine
to finish, it did not notify the recvRoutine that the connection was shutting
down. This would cause the recvRouting to receive and error when reading and
log this error. The changeset fixes this by notifying the recvRoutine that
the connection is shutting down.

The second occurs when the connection is terminated (gracefully) by the other side.
The recvRoutine would get an EOF error during the read, log it, and stop the connection
with an error. The changeset detects EOF and gracefully shuts down the connection.

* bring back the comment about flushing

* add changelog entry

* listen for quitRecvRoutine too

* we have to call stopForError

Otherwise peer won't be removed from the peer set and maybe readded
later.
2019-08-01 10:28:32 -07:00
Marko
58c3e590b4 types: move MakeVote / MakeBlock functions (#3819)
to the types package

Paritally Fixes #3584
2019-08-01 10:28:32 -07:00
Marko
ff9e08a32f add staticcheck linting (#3828)
cleanup to add linter

    grpc change:
        https://godoc.org/google.golang.org/grpc#WithContextDialer
        https://godoc.org/google.golang.org/grpc#WithDialer
        grpc/grpc-go#2627
    prometheous change:
        due to UninstrumentedHandler, being deprecated in the future
    empty branch = empty if or else statement
        didn't delete them entirely but commented
        couldn't find a reason to have them
    could not replicate the issue #3406
        but if want to keep it commented then we should comment out the if statement as well
2019-08-01 10:28:32 -07:00
Anton Kaliaev
0335add437 docs: add guides to docs (#3830) 2019-08-01 10:28:32 -07:00
Marko
5d0e7034e8 Renamed wire.go to codec.go (#3827)
* Renamed wire.go to codec.go

- Wire was the previous name of amino
- Codec describes the file better than `wire` & `amino`

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

* ide error

* rename amino.go to codec.go
2019-08-01 10:28:32 -07:00
Anca Zamfir
abc30821f4 blockchain: Reorg reactor (#3561)
* go routines in blockchain reactor

* Added reference to the go routine diagram

* Initial commit

* cleanup

* Undo testing_logger change, committed by mistake

* Fix the test loggers

* pulled some fsm code into pool.go

* added pool tests

* changes to the design

added block requests under peer

moved the request trigger in the reactor poolRoutine, triggered now by a ticker

in general moved everything required for making block requests smarter in the poolRoutine

added a simple map of heights to keep track of what will need to be requested next

added a few more tests

* send errors to FSM in a different channel than blocks

send errors (RemovePeer) from switch on a different channel than the
one receiving blocks
renamed channels
added more pool tests

* more pool tests

* lint errors

* more tests

* more tests

* switch fast sync to new implementation

* fixed data race in tests

* cleanup

* finished fsm tests

* address golangci comments :)

* address golangci comments :)

* Added timeout on next block needed to advance

* updating docs and cleanup

* fix issue in test from previous cleanup

* cleanup

* Added termination scenarios, tests and more cleanup

* small fixes to adr, comments and cleanup

* Fix bug in sendRequest()

If we tried to send a request to a peer not present in the switch, a
missing continue statement caused the request to be blackholed in a peer
that was removed and never retried.

While this bug was manifesting, the reactor kept asking for other
blocks that would be stored and never consumed. Added the number of
unconsumed blocks in the math for requesting blocks ahead of current
processing height so eventually there will be no more blocks requested
until the already received ones are consumed.

* remove bpPeer's didTimeout field

* Use distinct err codes for peer timeout and FSM timeouts

* Don't allow peers to update with lower height

* review comments from Ethan and Zarko

* some cleanup, renaming, comments

* Move block execution in separate goroutine

* Remove pool's numPending

* review comments

* fix lint, remove old blockchain reactor and duplicates in fsm tests

* small reorg around peer after review comments

* add the reactor spec

* verify block only once

* review comments

* change to int for max number of pending requests

* cleanup and godoc

* Add configuration flag fast sync version

* golangci fixes

* fix config template

* move both reactor versions under blockchain

* cleanup, golint, renaming stuff

* updated documentation, fixed more golint warnings

* integrate with behavior package

* sync with master

* gofmt

* add changelog_pending entry

* move to improvments

* suggestion to changelog entry
2019-08-01 10:28:32 -07:00
Anton Kaliaev
e89991c445 rpc: return err if page is incorrect (less than 0 or greater than tot… (#3825)
* rpc: return err if page is incorrect (less than 0 or greater than total pages)

Fixes #3813

* fix rpc_test
2019-08-01 10:28:32 -07:00
Jun Kimura
df6df61ea9 mempool: make max_msg_bytes configurable (#3826)
* mempool: make max_msg_bytes configurable

* apply suggestions from code review

* update changelog pending

* apply suggestions from code review again
2019-08-01 10:28:32 -07:00
Anton Kaliaev
5ed39fd0b3 rpc: /broadcast_evidence (#3481)
* implement broadcast_duplicate_vote endpoint

* fix test_cover

* address comments

* address comments

* Update abci/example/kvstore/persistent_kvstore.go

Co-Authored-By: mossid <torecursedivine@gmail.com>

* Update rpc/client/main_test.go

Co-Authored-By: mossid <torecursedivine@gmail.com>

* address comments in progress

* reformat the code

* make linter happy

* make tests pass

* replace BroadcastDuplicateVote with BroadcastEvidence

* fix test

* fix endpoint name

* improve doc

* fix TestBroadcastEvidenceDuplicateVote

* Update rpc/core/evidence.go

Co-Authored-By: Thane Thomson <connect@thanethomson.com>

* add changelog entry

* fix TestBroadcastEvidenceDuplicateVote
2019-08-01 10:28:32 -07:00
zjubfd
17b69d4d56 p2p/conn: Add Bufferpool (#3664)
* use byte buffer pool to decreass allocs

* wrap to put buffer in defer

* wapper defer

* add dependency

* remove Gopkg,*

* add change log
2019-08-01 10:28:32 -07:00
Jun Kimura
5d7e22a53c rpc: make max_body_bytes and max_header_bytes configurable (#3818)
* rpc: make max_body_bytes and max_header_bytes configurable

* update changelog pending
2019-08-01 10:28:32 -07:00
Marko
073cd1125e docs: add A TOC to the Readme.md of ADR Section (#3820)
* ADR TOC in readme.md

* Added A TOC to the Readme.md of ADR Section

- Added table of contents to the Readme of the architecture section.
	- Easier to traverse and when you know what is there.
	- If the Adr's become viewable online it would help guide the user

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

* add tm-cmn to subprojects

* normalize word
2019-08-01 10:28:32 -07:00
Marko
7041001fb6 libs: Remove db from tendermint in favor of tendermint/tm-cmn (#3811)
* Remove db from tendemrint in favor of tendermint/tm-cmn

- remove db from `libs`
- update dependancy, there have been no breaking changes in the updated deps
	- https://github.com/grpc/grpc-go/releases
	- https://github.com/golang/protobuf/releases

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

* changelog add

* gofmt

* more gofmt
2019-08-01 10:28:32 -07:00
Anton Kaliaev
c264db339e docs: "Writing a built-in Tendermint Core application in Go" guide (#3608)
* docs: go built-in guide

* fix package imports, add badger db, simplify Query

* newTendermint function

* working example

* finish the first guide

* add one more note

* add the second Golang guide - external ABCI app

* fix typos
2019-08-01 10:28:32 -07:00
Marko
8da43508f8 abci/client: fix DATA RACE in gRPC client (#3798)
* Remove go func {}()

closes #357

- Remove go func(){}() that caused race condiditon

- To reproduce
	- add -race in make file to `install_abci`
	- Remove `CGO_ENABLED=0` & add -race to `install`

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

* remove -race

* fix data race

also, reorder callbacks similarly to socket client
2019-08-01 10:28:32 -07:00
Roman Useinov
9867a65de7 abci/server: recover from app panics in socket server (#3809)
fixes #3800
2019-08-01 10:28:32 -07:00
Alex Dupre
9df117748e docs: fix consensus spec formatting (#3804) 2019-08-01 10:28:32 -07:00
68 changed files with 6391 additions and 5612 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,445 +0,0 @@
version: 2.1
executors:
golang:
docker:
- image: tendermintdev/docker-tendermint-build
working_directory: /go/src/github.com/tendermint/tendermint
environment:
GOBIN: /tmp/bin
release:
machine: true
docs:
docker:
- image: tendermintdev/docker-website-deployment
environment:
AWS_REGION: us-east-1
commands:
run_test:
parameters:
script_path:
type: string
steps:
- attach_workspace:
at: /tmp/bin
- restore_cache:
name: "Restore source code cache"
keys:
- go-src-v1-{{ .Revision }}
- checkout
- restore_cache:
name: "Restore go modules cache"
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: "Running test"
command: |
bash << parameters.script_path >>
jobs:
setup_dependencies:
executor: golang
steps:
- checkout
- restore_cache:
name: "Restore go modules cache"
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
command: |
mkdir -p /tmp/bin
- run:
name: Cache go modules
command: make go-mod-cache
- run:
name: tools
command: make tools
- run:
name: "Build binaries"
command: make install install_abci
- save_cache:
name: "Save go modules cache"
key: go-mod-v1-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
- save_cache:
name: "Save source code cache"
key: go-src-v1-{{ .Revision }}
paths:
- ".git"
- persist_to_workspace:
root: "/tmp/bin"
paths:
- "."
test_abci_apps:
executor: golang
steps:
- run_test:
script_path: abci/tests/test_app/test.sh
# if this test fails, fix it and update the docs at:
# https://github.com/tendermint/tendermint/blob/master/docs/abci-cli.md
test_abci_cli:
executor: golang
steps:
- run_test:
script_path: abci/tests/test_cli/test.sh
test_apps:
executor: golang
steps:
- run_test:
script_path: test/app/test.sh
test_persistence:
executor: golang
steps:
- run_test:
script_path: test/persist/test_failure_indices.sh
test_cover:
executor: golang
parallelism: 4
steps:
- restore_cache:
name: "Restore source code cache"
keys:
- go-src-v1-{{ .Revision }}
- checkout
- restore_cache:
name: "Restore go module cache"
keys:
- go-mod-v2-{{ checksum "go.sum" }}
- run:
name: "Run tests"
command: |
export VERSION="$(git describe --tags --long | sed 's/v\(.*\)/\1/')"
export GO111MODULE=on
mkdir -p /tmp/logs /tmp/workspace/profiles
for pkg in $(go list github.com/tendermint/tendermint/... | circleci tests split --split-by=timings); do
id=$(basename "$pkg")
go test -v -timeout 5m -mod=readonly -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" | tee "/tmp/logs/$id-$RANDOM.log"
done
- persist_to_workspace:
root: /tmp/workspace
paths:
- "profiles/*"
- store_artifacts:
path: /tmp/logs
localnet:
working_directory: /home/circleci/.go_workspace/src/github.com/tendermint/tendermint
machine:
image: circleci/classic:latest
environment:
GOBIN: /home/circleci/.go_workspace/bin
GOPATH: /home/circleci/.go_workspace/
GOOS: linux
GOARCH: amd64
parallelism: 1
steps:
- checkout
- run:
name: run localnet and exit on failure
command: |
set -x
docker run --rm -v "$PWD":/go/src/github.com/tendermint/tendermint -w /go/src/github.com/tendermint/tendermint golang make build-linux
make localnet-start &
./scripts/localnet-blocks-test.sh 40 5 10 localhost
test_p2p:
environment:
GOBIN: /home/circleci/.go_workspace/bin
GOPATH: /home/circleci/.go_workspace
machine:
image: circleci/classic:latest
steps:
- checkout
- run: mkdir -p $GOPATH/src/github.com/tendermint
- run: ln -sf /home/circleci/project $GOPATH/src/github.com/tendermint/tendermint
- run: bash test/p2p/circleci.sh
- store_artifacts:
path: /home/circleci/project/test/p2p/logs
upload_coverage:
executor: golang
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
name: "Restore source code cache"
keys:
- go-src-v1-{{ .Revision }}
- checkout
- restore_cache:
name: "Restore go module cache"
keys:
- go-mod-v2-{{ checksum "go.sum" }}
- run:
name: gather
command: |
echo "mode: atomic" > coverage.txt
for prof in $(ls /tmp/workspace/profiles/); do
tail -n +2 /tmp/workspace/profiles/"$prof" >> coverage.txt
done
- run:
name: upload
command: bash .circleci/codecov.sh -f coverage.txt
deploy_docs:
executor: docs
steps:
- checkout
- run:
name: "Build docs"
command: make build-docs
- run:
name: "Sync to S3"
command: make sync-docs
prepare_build:
executor: golang
steps:
- restore_cache:
name: "Restore source code cache"
keys:
- go-src-v1-{{ .Revision }}
- checkout
- run:
name: Get next release number
command: |
export LAST_TAG="`git describe --tags --abbrev=0 --match "${CIRCLE_BRANCH}.*"`"
echo "Last tag: ${LAST_TAG}"
if [ -z "${LAST_TAG}" ]; then
export LAST_TAG="${CIRCLE_BRANCH}"
echo "Last tag not found. Possibly fresh branch or feature branch. Setting ${LAST_TAG} as tag."
fi
export NEXT_TAG="`python -u scripts/release_management/bump-semver.py --version "${LAST_TAG}"`"
echo "Next tag: ${NEXT_TAG}"
echo "export CIRCLE_TAG=\"${NEXT_TAG}\"" > release-version.source
- run:
name: Build dependencies
command: make tools
- persist_to_workspace:
root: .
paths:
- "release-version.source"
- save_cache:
key: v2-release-deps-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
build_artifacts:
executor: golang
parallelism: 4
steps:
- restore_cache:
name: "Restore source code cache"
keys:
- go-src-v1-{{ .Revision }}
- checkout
- restore_cache:
name: "Restore release dependencies cache"
keys:
- v2-release-deps-{{ checksum "go.sum" }}
- attach_workspace:
at: /tmp/workspace
- run:
name: Build artifact
command: |
# Setting CIRCLE_TAG because we do not tag the release ourselves.
source /tmp/workspace/release-version.source
if test ${CIRCLE_NODE_INDEX:-0} == 0 ;then export GOOS=linux GOARCH=amd64 && export OUTPUT=build/tendermint_${GOOS}_${GOARCH} && make build && python -u scripts/release_management/zip-file.py ;fi
if test ${CIRCLE_NODE_INDEX:-0} == 1 ;then export GOOS=darwin GOARCH=amd64 && export OUTPUT=build/tendermint_${GOOS}_${GOARCH} && make build && python -u scripts/release_management/zip-file.py ;fi
if test ${CIRCLE_NODE_INDEX:-0} == 2 ;then export GOOS=windows GOARCH=amd64 && export OUTPUT=build/tendermint_${GOOS}_${GOARCH} && make build && python -u scripts/release_management/zip-file.py ;fi
if test ${CIRCLE_NODE_INDEX:-0} == 3 ;then export GOOS=linux GOARCH=arm && export OUTPUT=build/tendermint_${GOOS}_${GOARCH} && make build && python -u scripts/release_management/zip-file.py ;fi
- persist_to_workspace:
root: build
paths:
- "*.zip"
- "tendermint_linux_amd64"
release_artifacts:
executor: golang
steps:
- restore_cache:
name: "Restore source code cache"
keys:
- go-src-v1-{{ .Revision }}
- checkout
- attach_workspace:
at: /tmp/workspace
- run:
name: "Deploy to GitHub"
command: |
# Setting CIRCLE_TAG because we do not tag the release ourselves.
source /tmp/workspace/release-version.source
echo "---"
ls -la /tmp/workspace/*.zip
echo "---"
python -u scripts/release_management/sha-files.py
echo "---"
cat /tmp/workspace/SHA256SUMS
echo "---"
export RELEASE_ID="`python -u scripts/release_management/github-draft.py`"
echo "Release ID: ${RELEASE_ID}"
#Todo: Parallelize uploads
export GOOS=linux GOARCH=amd64 && python -u scripts/release_management/github-upload.py --id "${RELEASE_ID}"
export GOOS=darwin GOARCH=amd64 && python -u scripts/release_management/github-upload.py --id "${RELEASE_ID}"
export GOOS=windows GOARCH=amd64 && python -u scripts/release_management/github-upload.py --id "${RELEASE_ID}"
export GOOS=linux GOARCH=arm && python -u scripts/release_management/github-upload.py --id "${RELEASE_ID}"
python -u scripts/release_management/github-upload.py --file "/tmp/workspace/SHA256SUMS" --id "${RELEASE_ID}"
python -u scripts/release_management/github-publish.py --id "${RELEASE_ID}"
release_docker:
machine:
image: ubuntu-1604:201903-01
steps:
- checkout
- attach_workspace:
at: /tmp/workspace
- run:
name: "Deploy to Docker Hub"
command: |
# Setting CIRCLE_TAG because we do not tag the release ourselves.
source /tmp/workspace/release-version.source
cp /tmp/workspace/tendermint_linux_amd64 DOCKER/tendermint
docker build --label="tendermint" --tag="tendermint/tendermint:${CIRCLE_TAG}" --tag="tendermint/tendermint:latest" "DOCKER"
docker login -u "${DOCKERHUB_USER}" --password-stdin \<<< "${DOCKERHUB_PASS}"
docker push "tendermint/tendermint"
docker logout
reproducible_builds:
executor: golang
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- setup_remote_docker:
docker_layer_caching: true
- run:
name: Build tendermint
no_output_timeout: 20m
command: |
sudo apt-get install -y ruby
bash -x ./scripts/gitian-build.sh all
for os in darwin linux windows; do
cp gitian-build-${os}/result/tendermint-${os}-res.yml .
cp gitian-build-${os}/build/out/tendermint-*.tar.gz .
rm -rf gitian-build-${os}/
done
- store_artifacts:
path: /go/src/github.com/tendermint/tendermint/tendermint-darwin-res.yml
- store_artifacts:
path: /go/src/github.com/tendermint/tendermint/tendermint-linux-res.yml
- store_artifacts:
path: /go/src/github.com/tendermint/tendermint/tendermint-windows-res.yml
- store_artifacts:
path: /go/src/github.com/tendermint/tendermint/tendermint-*.tar.gz
# Test RPC implementation against the swagger documented specs
contract_tests:
working_directory: /home/circleci/.go_workspace/src/github.com/tendermint/tendermint
machine:
image: circleci/classic:latest
environment:
GOBIN: /home/circleci/.go_workspace/bin
GOPATH: /home/circleci/.go_workspace/
GOOS: linux
GOARCH: amd64
parallelism: 1
steps:
- checkout
- run:
name: Test RPC endpoints against swagger documentation
command: |
set -x
export PATH=~/.local/bin:$PATH
# install node and dredd
./scripts/get_nodejs.sh
# build the binaries with a proper version of Go
docker run --rm -v "$PWD":/go/src/github.com/tendermint/tendermint -w /go/src/github.com/tendermint/tendermint golang make build-linux build-contract-tests-hooks
# This docker image works with go 1.7, we can install here the hook handler that contract-tests is going to use
go get github.com/snikch/goodman/cmd/goodman
make contract-tests
workflows:
version: 2
test-suite:
jobs:
- deploy_docs:
context: tendermint-docs
filters:
branches:
only:
- master
tags:
only:
- /^v.*/
- deploy_docs:
context: tendermint-docs-staging
filters:
branches:
only:
- docs-theme-latest
- setup_dependencies
- test_abci_apps:
requires:
- setup_dependencies
- test_abci_cli:
requires:
- setup_dependencies
- test_apps:
requires:
- setup_dependencies
- test_cover:
requires:
- setup_dependencies
- test_persistence:
requires:
- setup_dependencies
- localnet:
requires:
- setup_dependencies
- test_p2p
- upload_coverage:
requires:
- test_cover
- reproducible_builds:
filters:
branches:
only:
- master
- /v[0-9]+\.[0-9]+/
- contract_tests:
requires:
- setup_dependencies
release:
jobs:
- prepare_build
- build_artifacts:
requires:
- prepare_build
- release_artifacts:
requires:
- prepare_build
- build_artifacts
filters:
branches:
only:
- /v[0-9]+\.[0-9]+/
- release_docker:
requires:
- prepare_build
- build_artifacts
filters:
branches:
only:
- /v[0-9]+\.[0-9]+/
- master

8
.github/linter/markdownlint.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
default: true,
MD007: { "indent": 4 }
MD013: false
MD024: { siblings_only: true }
MD025: false
MD033: { no-inline-html: false }
no-hard-tabs: false
whitespace: false

127
.github/workflows/coverage.yml vendored Normal file
View File

@@ -0,0 +1,127 @@
name: Test Coverage
on:
pull_request:
push:
branches:
- master
- release/**
jobs:
split-test-files:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Create a file with all the pkgs
run: go list ./... > pkgs.txt
- name: Split pkgs into 4 files
run: split -d -n l/4 pkgs.txt pkgs.txt.part.
# cache multiple
- uses: actions/upload-artifact@v2
with:
name: "${{ github.sha }}-00"
path: ./pkgs.txt.part.00
- uses: actions/upload-artifact@v2
with:
name: "${{ github.sha }}-01"
path: ./pkgs.txt.part.01
- uses: actions/upload-artifact@v2
with:
name: "${{ github.sha }}-02"
path: ./pkgs.txt.part.02
- uses: actions/upload-artifact@v2
with:
name: "${{ github.sha }}-03"
path: ./pkgs.txt.part.03
build-linux:
name: Build
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
goarch: ["arm", "amd64"]
timeout-minutes: 5
steps:
- uses: actions/setup-go@v2
with:
go-version: "1.15"
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: install
run: GOOS=linux GOARCH=${{ matrix.goarch }} make build
if: "env.GIT_DIFF != ''"
tests:
runs-on: ubuntu-latest
needs: split-test-files
strategy:
fail-fast: false
matrix:
part: ["00", "01", "02", "03"]
steps:
- uses: actions/setup-go@v2
with:
go-version: "1.15"
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- uses: actions/download-artifact@v2
with:
name: "${{ github.sha }}-${{ matrix.part }}"
if: env.GIT_DIFF
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.15
- name: test & coverage report creation
run: |
cat pkgs.txt.part.${{ matrix.part }} | xargs go test -mod=readonly -timeout 8m -race -coverprofile=${{ matrix.part }}profile.out -covermode=atomic
if: env.GIT_DIFF
- uses: actions/upload-artifact@v2
with:
name: "${{ github.sha }}-${{ matrix.part }}-coverage"
path: ./${{ matrix.part }}profile.out
upload-coverage-report:
runs-on: ubuntu-latest
needs: tests
steps:
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- uses: actions/download-artifact@v2
with:
name: "${{ github.sha }}-00-coverage"
if: env.GIT_DIFF
- uses: actions/download-artifact@v2
with:
name: "${{ github.sha }}-01-coverage"
if: env.GIT_DIFF
- uses: actions/download-artifact@v2
with:
name: "${{ github.sha }}-02-coverage"
if: env.GIT_DIFF
- uses: actions/download-artifact@v2
with:
name: "${{ github.sha }}-03-coverage"
if: env.GIT_DIFF
- run: |
cat ./*profile.out | grep -v "mode: atomic" >> coverage.txt
if: env.GIT_DIFF
- uses: codecov/codecov-action@v1.0.15
with:
file: ./coverage.txt
if: env.GIT_DIFF

59
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
name: Build & Push
# Build & Push rebuilds the tendermint docker image on every push to master and creation of tags
# and pushes the image to https://hub.docker.com/r/interchainio/simapp/tags
on:
pull_request:
push:
branches:
- master
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
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v2
with:
go-version: "1.15"
- uses: actions/checkout@master
- name: Prepare
id: prep
run: |
DOCKER_IMAGE=tendermint/tendermint
VERSION=noop
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
elif [[ $GITHUB_REF == refs/heads/* ]]; then
VERSION=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's#/+#-#g')
if [ "${{ github.event.repository.default_branch }}" = "$VERSION" ]; then
VERSION=latest
fi
fi
TAGS="${DOCKER_IMAGE}:${VERSION}"
if [[ $VERSION =~ ^v[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
TAGS="$TAGS,${DOCKER_IMAGE}:${VERSION}"
fi
echo ::set-output name=tags::${TAGS}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Tendermint
run: |
make build-linux && cp build/tendermint DOCKER/tendermint
- name: Publish to Docker Hub
uses: docker/build-push-action@v2
with:
context: ./DOCKER
file: ./DOCKER/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.prep.outputs.tags }}

12
.github/workflows/linkchecker.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
name: Check Markdown links
on:
schedule:
- cron: '* */24 * * *'
jobs:
markdown-link-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: gaurav-nelson/github-action-markdown-link-check@1.0.8
with:
folder-path: "docs"

29
.github/workflows/lint.yaml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: Lint
# Lint runs golangci-lint over the entire Tendermint repository
# This workflow is run on every pull request and push to master
# The `golangci` job will pass without running if no *.{go, mod, sum} files have been modified.
on:
pull_request:
push:
branches:
- master
jobs:
golangci:
name: golangci-lint
runs-on: ubuntu-latest
timeout-minutes: 4
steps:
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- uses: golangci/golangci-lint-action@v1
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.26
args: --timeout 10m
github-token: ${{ secrets.github_token }}
if: env.GIT_DIFF

31
.github/workflows/linter.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Lint
on:
push:
branches:
- master
paths:
- "**.md"
- "**.yml"
- "**.yaml"
pull_request:
branches: [master]
paths:
- "**.md"
jobs:
build:
name: Super linter
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Lint Code Base
uses: docker://github/super-linter:v3
env:
LINTER_RULES_PATH: .
VALIDATE_ALL_CODEBASE: true
DEFAULT_BRANCH: master
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VALIDATE_MD: true
VALIDATE_OPAENAPI: true
VALIDATE_YAML: true

29
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: "Release"
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-go@v2
with:
go-version: '1.15'
- run: echo https://github.com/tendermint/tendermint/blob/${GITHUB_REF#refs/tags/}/CHANGELOG.md#${GITHUB_REF#refs/tags/} > ../release_notes.md
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist --release-notes=../release_notes.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

18
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: "Close stale pull requests"
on:
schedule:
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: "This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions."
days-before-stale: 10
days-before-close: 4
exempt-pr-labels: "S:wip"

146
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,146 @@
name: Tests
# Tests runs different tests (test_abci_apps, test_abci_cli, test_apps)
# This workflow runs on every push to master or release branch and every pull requests
# All jobs will pass without running if no *{.go, .mod, .sum} files have been modified
on:
pull_request:
push:
branches:
- master
- release/**
jobs:
cleanup-runs:
runs-on: ubuntu-latest
steps:
- uses: rokroskar/workflow-run-cleanup-action@master
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master'"
build:
name: Build
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/setup-go@v2
with:
go-version: "1.15"
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: install
run: make install install_abci
if: "env.GIT_DIFF != ''"
- uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
if: env.GIT_DIFF
# Cache binaries for use by other jobs
- uses: actions/cache@v2.1.3
with:
path: ~/go/bin
key: ${{ runner.os }}-${{ github.sha }}-tm-binary
if: env.GIT_DIFF
test_abci_apps:
runs-on: ubuntu-latest
needs: build
timeout-minutes: 5
steps:
- uses: actions/setup-go@v2
with:
go-version: "1.15"
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
if: env.GIT_DIFF
- uses: actions/cache@v2.1.3
with:
path: ~/go/bin
key: ${{ runner.os }}-${{ github.sha }}-tm-binary
if: env.GIT_DIFF
- name: test_abci_apps
run: abci/tests/test_app/test.sh
shell: bash
if: env.GIT_DIFF
test_abci_cli:
runs-on: ubuntu-latest
needs: build
timeout-minutes: 5
steps:
- uses: actions/setup-go@v2
with:
go-version: "1.15"
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
if: env.GIT_DIFF
- uses: actions/cache@v2.1.3
with:
path: ~/go/bin
key: ${{ runner.os }}-${{ github.sha }}-tm-binary
if: env.GIT_DIFF
- run: abci/tests/test_cli/test.sh
shell: bash
if: env.GIT_DIFF
test_apps:
runs-on: ubuntu-latest
needs: build
timeout-minutes: 5
steps:
- uses: actions/setup-go@v2
with:
go-version: "1.15"
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
if: env.GIT_DIFF
- uses: actions/cache@v2.1.3
with:
path: ~/go/bin
key: ${{ runner.os }}-${{ github.sha }}-tm-binary
if: env.GIT_DIFF
- name: test_apps
run: test/app/test.sh
shell: bash
if: env.GIT_DIFF

View File

@@ -16,14 +16,14 @@ linters:
- gofmt
- goimports
# - golint
- gosec
# - gosec
- gosimple
- govet
- ineffassign
- interfacer
- lll
- misspell
- maligned
# - maligned
- nakedret
- prealloc
- scopelint
@@ -83,3 +83,5 @@ linters-settings:
# disabled-checks:
# - wrapperFunc
# - commentFormatting # https://github.com/go-critic/go-critic/issues/755
service:
golangci-lint-version: 1.26.x

28
.goreleaser.yml Normal file
View File

@@ -0,0 +1,28 @@
project_name: Tendermint
env:
# Require use of Go modules.
- GO111MODULE=on
builds:
- id: "Tendermint"
main: ./cmd/tendermint/main.go
ldflags:
- -s -w -X github.com/tendermint/tendermint/version.TMCoreSemVer={{ .Version }}
env:
- CGO_ENABLED=0
goos:
- darwin
- linux
- windows
goarch:
- amd64
- arm
- arm64
checksum:
name_template: SHA256SUMS-{{.Version}}.txt
algorithm: sha256
release:
name_template: "{{.Version}} (WARNING: BETA SOFTWARE)"

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
## v0.32.8
## v0.32.15
\*\*
Special thanks to external contributors on this release:
@erikgrinaker
Friendly reminder, we have a [bug bounty
program](https://hackerone.com/tendermint).
@@ -15,24 +14,12 @@ program](https://hackerone.com/tendermint).
- Apps
- Go API
- [libs/pubsub] [\#4070](https://github.com/tendermint/tendermint/pull/4070) `Query#(Matches|Conditions)` returns an error.
### FEATURES:
### IMPROVEMENTS:
- [mempool] [\#4083](https://github.com/tendermint/tendermint/pull/4083) Added TxInfo parameter to CheckTx(), and removed CheckTxWithInfo() (@erikgrinaker)
- [mempool] [\#4057](https://github.com/tendermint/tendermint/issues/4057) Include peer ID when logging rejected txns (@erikgrinaker)
- [tools] [\#4023](https://github.com/tendermint/tendermint/issues/4023) Improved `tm-monitor` formatting of start time and avg tx throughput (@erikgrinaker)
- [libs/pubsub] [\#4070](https://github.com/tendermint/tendermint/pull/4070) No longer panic in `Query#(Matches|Conditions)` preferring to return an error instead.
- [libs/pubsub] [\#4070](https://github.com/tendermint/tendermint/pull/4070) Strip out non-numeric characters when attempting to match numeric values.
- [p2p] [\#3991](https://github.com/tendermint/tendermint/issues/3991) Log "has been established or dialed" as debug log instead of Error for connected peers (@whunmr)
- [rpc] [\#4077](https://github.com/tendermint/tendermint/pull/4077) Added support for `EXISTS` clause to the Websocket query interface.
- [privval] Add `SignerDialerEndpointRetryWaitInterval` option (@cosmostuba)
- [crypto] Add `RegisterKeyType` to amino to allow external key types registration (@austinabell)
### BUG FIXES:
- [tools] [\#4023](https://github.com/tendermint/tendermint/issues/4023) Refresh `tm-monitor` health when validator count is updated (@erikgrinaker)
- [state] [\#4104](https://github.com/tendermint/tendermint/pull/4104) txindex/kv: Fsync data to disk immediately after receiving it (@guagualvcha)
- [state] [\#4095](https://github.com/tendermint/tendermint/pull/4095) txindex/kv: Return an error if there's one when the user searches for a tx (hash=X) (@hsyis)
- [blockchain/v1] [\#5701](https://github.com/tendermint/tendermint/pull/5701) Handle peers without blocks (@melekes)
- [blockchain/v1] \#5711 Fix deadlock (@melekes)

View File

@@ -53,7 +53,7 @@ func testCounter() {
}
fmt.Printf("Running %s test with abci=%s\n", abciApp, abciType)
cmd := exec.Command("bash", "-c", fmt.Sprintf("abci-cli %s", abciApp))
cmd := exec.Command("bash", "-c", fmt.Sprintf("abci-cli %s", abciApp)) //nolint:gosec
cmd.Stdout = os.Stdout
if err := cmd.Start(); err != nil {
log.Fatalf("starting %q err: %v", abciApp, err)

View File

@@ -176,7 +176,7 @@ func (bcR *BlockchainReactor) respondToPeer(msg *bcBlockRequestMessage,
func (bcR *BlockchainReactor) 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, "msg", msg, "err", err, "bytes", msgBytes)
bcR.Logger.Error("Error decoding message", "src", src, "chId", chID, "err", err)
bcR.Switch.StopPeerForError(src, err)
return
}

View File

@@ -30,6 +30,7 @@ type BpPeer struct {
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
noBlocks map[int64]struct{} // heights for which the peer does not have blocks
blockResponseTimer *time.Timer
recvMonitor *flow.Monitor
params *BpPeerParams // parameters for timer and monitor
@@ -45,12 +46,13 @@ func NewBpPeer(
params = BpPeerDefaultParams()
}
return &BpPeer{
ID: peerID,
Height: height,
blocks: make(map[int64]*types.Block, maxRequestsPerPeer),
logger: log.NewNopLogger(),
onErr: onErr,
params: params,
ID: peerID,
Height: height,
blocks: make(map[int64]*types.Block, maxRequestsPerPeer),
noBlocks: make(map[int64]struct{}),
logger: log.NewNopLogger(),
onErr: onErr,
params: params,
}
}
@@ -129,6 +131,19 @@ func (peer *BpPeer) RemoveBlock(height int64) {
delete(peer.blocks, height)
}
// SetNoBlock records that the peer does not have a block for height.
func (peer *BpPeer) SetNoBlock(height int64) {
peer.noBlocks[height] = struct{}{}
}
// NoBlock returns true if the peer does not have a block for height.
func (peer *BpPeer) NoBlock(height int64) bool {
if _, ok := peer.noBlocks[height]; ok {
return true
}
return false
}
// 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

View File

@@ -99,6 +99,18 @@ func (pool *BlockPool) UpdatePeer(peerID p2p.ID, height int64) error {
return nil
}
// SetNoBlock records that the peer does not have a block for height and
// schedules a new request for that height from another peer.
func (pool *BlockPool) SetNoBlock(peerID p2p.ID, height int64) {
peer := pool.peers[peerID]
if peer == nil {
return
}
peer.SetNoBlock(height)
pool.rescheduleRequest(peerID, height)
}
// Cleans and deletes the peer. Recomputes the max peer height.
func (pool *BlockPool) deletePeer(peer *BpPeer) {
if peer == nil {
@@ -213,7 +225,7 @@ func (pool *BlockPool) sendRequest(height int64) bool {
if peer.NumPendingBlockRequests >= maxRequestsPerPeer {
continue
}
if peer.Height < height {
if peer.Height < height || peer.NoBlock(height) {
continue
}

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"reflect"
"sync/atomic"
"time"
amino "github.com/tendermint/go-amino"
@@ -73,6 +74,9 @@ type BlockchainReactor struct {
eventsFromFSMCh chan bcFsmMessage
swReporter *behaviour.SwitchReporter
// Atomic integer (0 - sync in progress, 1 - finished syncing)
syncEnded int32
}
// NewBlockchainReactor returns new reactor instance.
@@ -144,13 +148,22 @@ func (bcR *BlockchainReactor) OnStart() error {
bcR.swReporter = behaviour.NewSwitcReporter(bcR.BaseReactor.Switch)
if bcR.fastSync {
go bcR.poolRoutine()
} else { // if we're not fast syncing, mark it as finished
bcR.setSyncEnded()
}
return nil
}
// OnStop implements cmn.Service.
func (bcR *BlockchainReactor) OnStop() {
_ = bcR.Stop()
}
func (bcR *BlockchainReactor) isSyncEnded() bool {
return atomic.LoadInt32(&(bcR.syncEnded)) != 0
}
func (bcR *BlockchainReactor) setSyncEnded() {
atomic.StoreInt32(&(bcR.syncEnded), 1)
}
// GetChannels implements Reactor
@@ -201,6 +214,10 @@ func (bcR *BlockchainReactor) sendStatusResponseToPeer(msg *bcStatusRequestMessa
// RemovePeer implements Reactor by removing peer from the pool.
func (bcR *BlockchainReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
if bcR.isSyncEnded() {
return
}
msgData := bcReactorMessage{
event: peerRemoveEv,
data: bReactorEventData{
@@ -244,6 +261,10 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
}
case *bcBlockResponseMessage:
if bcR.isSyncEnded() {
return
}
msgForFSM := bcReactorMessage{
event: blockResponseEv,
data: bReactorEventData{
@@ -256,7 +277,26 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
bcR.Logger.Info("Received", "src", src, "height", msg.Block.Height)
bcR.messagesForFSMCh <- msgForFSM
case *bcNoBlockResponseMessage:
if bcR.isSyncEnded() {
return
}
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 *bcStatusResponseMessage:
if bcR.isSyncEnded() {
return
}
// Got a peer status. Unverified.
msgForFSM := bcReactorMessage{
event: statusResponseEv,
@@ -267,7 +307,6 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
},
}
bcR.messagesForFSMCh <- msgForFSM
default:
bcR.Logger.Error(fmt.Sprintf("unknown message type %v", reflect.TypeOf(msg)))
}
@@ -275,16 +314,20 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
// 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)
defer processReceivedBlockTicker.Stop()
lastHundred := time.Now()
lastRate := 0.0
var (
doProcessBlockCh = make(chan struct{}, 1)
lastHundred = time.Now()
lastRate = 0.0
)
ForLoop:
for {
select {
case <-bcR.Quit():
break ForLoop
case <-stopProcessing:
bcR.Logger.Info("finishing block execution")
break ForLoop
@@ -327,12 +370,14 @@ ForLoop:
// 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)
defer sendBlockRequestTicker.Stop()
// NOTE: statusUpdateTicker can continue to run
stopProcessing := make(chan struct{}, 1)
go bcR.processBlocksRoutine(stopProcessing)
@@ -365,12 +410,10 @@ ForLoop:
case msg := <-bcR.eventsFromFSMCh:
switch msg.event {
case syncFinishedEv:
case syncFinishedEv: // Sent from the FSM when it enters finished state.
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.setSyncEnded()
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
@@ -437,14 +480,12 @@ func (bcR *BlockchainReactor) processBlock() error {
return nil
}
// Implements bcRNotifier
// sendStatusRequest broadcasts `BlockStore` height.
func (bcR *BlockchainReactor) sendStatusRequest() {
msgBytes := cdc.MustMarshalBinaryBare(&bcStatusRequestMessage{bcR.store.Height()})
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)
@@ -460,19 +501,14 @@ func (bcR *BlockchainReactor) sendBlockRequest(peerID p2p.ID, height int64) erro
return nil
}
// Implements bcRNotifier
func (bcR *BlockchainReactor) switchToConsensus() {
conR, ok := bcR.Switch.Reactor("CONSENSUS").(consensusReactor)
if ok {
conR.SwitchToConsensus(bcR.state, bcR.blocksSynced)
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:
@@ -490,7 +526,6 @@ func (bcR *BlockchainReactor) sendPeerError(err error, peerID p2p.ID) {
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")

View File

@@ -73,6 +73,7 @@ const (
startFSMEv = iota + 1
statusResponseEv
blockResponseEv
noBlockResponseEv
processedBlockEv
makeRequestsEv
stopFSMEv
@@ -93,6 +94,9 @@ func (msg *bcReactorMessage) String() string {
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:
@@ -118,6 +122,8 @@ func (ev bReactorEvent) String() string {
return "statusResponseEv"
case blockResponseEv:
return "blockResponseEv"
case noBlockResponseEv:
return "noBlockResponseEv"
case processedBlockEv:
return "processedBlockEv"
case makeRequestsEv:
@@ -268,7 +274,11 @@ func init() {
return waitForPeer, err
}
return waitForBlock, err
case noBlockResponseEv:
fsm.logger.Error("peer does not have requested block", "peer", data.peerID)
fsm.pool.SetNoBlock(data.peerID, data.height)
return waitForBlock, nil
case processedBlockEv:
if data.err != nil {
first, second, _ := fsm.pool.FirstTwoBlocksAndPeers()

View File

@@ -100,6 +100,19 @@ func sProcessedBlockEv(current, expected string, reactorError error) fsmStepTest
}
}
func sNoBlockResponseEv(current, expected string, peerID p2p.ID, height int64, err error) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
event: noBlockResponseEv,
data: bReactorEventData{
peerID: peerID,
height: height,
},
wantState: expected,
wantErr: err,
}
}
func sStatusEv(current, expected string, peerID p2p.ID, height int64, err error) fsmStepTestValues {
return fsmStepTestValues{
currentState: current,
@@ -352,6 +365,46 @@ func TestFSMBlockVerificationFailure(t *testing.T) {
executeFSMTests(t, tests, false)
}
func TestFSMNoBlockResponse(t *testing.T) {
tests := []testFields{
{
name: "no block response",
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
sNoBlockResponseEv("waitForBlock", "waitForBlock", "P1", 1, nil),
sNoBlockResponseEv("waitForBlock", "waitForBlock", "P1", 2, nil),
sNoBlockResponseEv("waitForBlock", "waitForBlock", "P1", 3, nil),
// 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{
{
@@ -820,7 +873,7 @@ const (
maxRequestsPerPeerTest = 20
maxTotalPendingRequestsTest = 600
maxNumPeersTest = 1000
maxNumBlocksInChainTest = 10000 //should be smaller than 9999999
maxNumBlocksInChainTest = 10000 // should be smaller than 9999999
)
func makeCorrectTransitionSequenceWithRandomParameters() testFields {

View File

@@ -226,11 +226,9 @@ func TestFastSyncNoBlockResponse(t *testing.T) {
}
}
// 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.
// 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)

View File

@@ -97,7 +97,6 @@ func (r *Reactor) demux() {
func (r *Reactor) Stop() {
r.logger.Info("reactor stopping")
r.ticker.Stop()
r.scheduler.stop()
r.processor.stop()

View File

@@ -19,6 +19,9 @@ type Metrics struct {
// Height of the chain.
Height metrics.Gauge
// ValidatorLastSignedHeight of a validator.
ValidatorLastSignedHeight metrics.Gauge
// Number of rounds.
Rounds metrics.Gauge
@@ -26,6 +29,10 @@ type Metrics struct {
Validators metrics.Gauge
// Total power of all validators.
ValidatorsPower metrics.Gauge
// Power of a validator.
ValidatorPower metrics.Gauge
// Amount of blocks missed by a validator.
ValidatorMissedBlocks metrics.Gauge
// Number of validators who did not sign.
MissingValidators metrics.Gauge
// Total power of the missing validators.
@@ -81,12 +88,30 @@ func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
Name: "validators",
Help: "Number of validators.",
}, labels).With(labelsAndValues...),
ValidatorLastSignedHeight: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "validator_last_signed_height",
Help: "Last signed height for a validator",
}, append(labels, "validator_address")).With(labelsAndValues...),
ValidatorMissedBlocks: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "validator_missed_blocks",
Help: "Total missed blocks for a validator",
}, append(labels, "validator_address")).With(labelsAndValues...),
ValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "validators_power",
Help: "Total power of all validators.",
}, labels).With(labelsAndValues...),
ValidatorPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "validator_power",
Help: "Power of a validator",
}, append(labels, "validator_address")).With(labelsAndValues...),
MissingValidators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
@@ -163,10 +188,14 @@ func NopMetrics() *Metrics {
return &Metrics{
Height: discard.NewGauge(),
ValidatorLastSignedHeight: discard.NewGauge(),
Rounds: discard.NewGauge(),
Validators: discard.NewGauge(),
ValidatorsPower: discard.NewGauge(),
ValidatorPower: discard.NewGauge(),
ValidatorMissedBlocks: discard.NewGauge(),
MissingValidators: discard.NewGauge(),
MissingValidatorsPower: discard.NewGauge(),
ByzantineValidators: discard.NewGauge(),

View File

@@ -57,7 +57,7 @@ func NewConsensusReactor(consensusState *ConsensusState, fastSync bool, options
metrics: NopMetrics(),
}
conR.updateFastSyncingMetric()
conR.BaseReactor = *p2p.NewBaseReactor("ConsensusReactor", conR)
conR.BaseReactor = *p2p.NewBaseReactor("Consensus", conR)
for _, option := range options {
option(conR)
@@ -218,7 +218,7 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
msg, err := decodeMsg(msgBytes)
if err != nil {
conR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
conR.Logger.Error("Error decoding message", "src", src, "chId", chID, "err", err)
conR.Switch.StopPeerForError(src, err)
return
}
@@ -501,10 +501,12 @@ OUTER_LOOP:
if prs.ProposalBlockParts == nil {
blockMeta := conR.conS.blockStore.LoadBlockMeta(prs.Height)
if blockMeta == nil {
panic(fmt.Sprintf("Failed to load block %d when blockStore is at %d",
prs.Height, conR.conS.blockStore.Height()))
heightLogger.Error("Failed to load block meta",
"blockstoreHeight", conR.conS.blockStore.Height())
time.Sleep(conR.conS.config.PeerGossipSleepDuration)
} else {
ps.InitProposalBlockParts(blockMeta.BlockID.PartsHeader)
}
ps.InitProposalBlockParts(blockMeta.BlockID.PartsHeader)
// continue the loop since prs is a copy and not effected by this initialization
continue OUTER_LOOP
}

View File

@@ -888,7 +888,7 @@ func TestVoteSetMaj23MessageValidateBasic(t *testing.T) {
}
func TestVoteSetBitsMessageValidateBasic(t *testing.T) {
testCases := []struct { // nolint: maligned
testCases := []struct {
malleateFn func(*VoteSetBitsMessage)
expErr string
}{

View File

@@ -17,6 +17,7 @@ import (
cfg "github.com/tendermint/tendermint/config"
cstypes "github.com/tendermint/tendermint/consensus/types"
"github.com/tendermint/tendermint/crypto"
tmevents "github.com/tendermint/tendermint/libs/events"
"github.com/tendermint/tendermint/p2p"
sm "github.com/tendermint/tendermint/state"
@@ -31,6 +32,8 @@ var (
ErrInvalidProposalPOLRound = errors.New("Error invalid proposal POL round")
ErrAddingVote = errors.New("Error adding vote")
ErrVoteHeightMismatch = errors.New("Error vote height mismatch")
errPubKeyIsNotSet = errors.New("pubkey is not set. Look for \"Can't get private validator pubkey\" errors")
)
//-----------------------------------------------------------------------------
@@ -95,6 +98,9 @@ type ConsensusState struct {
mtx sync.RWMutex
cstypes.RoundState
state sm.State // State until height-1.
// privValidator pubkey, memoized for the duration of one block
// to avoid extra requests to HSM
privValidatorPubKey crypto.PubKey
// state changes may be triggered by: msgs from peers,
// msgs from ourself, or by timeouts
@@ -251,11 +257,17 @@ func (cs *ConsensusState) GetValidators() (int64, []*types.Validator) {
return cs.state.LastBlockHeight, cs.state.Validators.Copy().Validators
}
// SetPrivValidator sets the private validator account for signing votes.
// SetPrivValidator sets the private validator account for signing votes. It
// immediately requests pubkey and caches it.
func (cs *ConsensusState) SetPrivValidator(priv types.PrivValidator) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
cs.privValidator = priv
cs.mtx.Unlock()
if err := cs.updatePrivValidatorPubKey(); err != nil {
cs.Logger.Error("Can't get private validator pubkey", "err", err)
}
}
// SetTimeoutTicker sets the local timer. It may be useful to overwrite for testing.
@@ -920,8 +932,17 @@ func (cs *ConsensusState) enterPropose(height int64, round int) {
return
}
logger.Debug("This node is a validator")
if cs.privValidatorPubKey == nil {
// If this node is a validator & proposer in the current round, it will
// miss the opportunity to create a block.
logger.Error(fmt.Sprintf("enterPropose: %v", errPubKeyIsNotSet))
return
}
address := cs.privValidatorPubKey.Address()
// if not a validator, we're done
address := cs.privValidator.GetPubKey().Address()
if !cs.Validators.HasAddress(address) {
logger.Debug("This node is not a validator", "addr", address, "vals", cs.Validators)
return
@@ -1007,7 +1028,12 @@ func (cs *ConsensusState) isProposalComplete() bool {
// is returned for convenience so we can log the proposal block.
// Returns nil block upon error.
// NOTE: keep it side-effect free for clarity.
// CONTRACT: cs.privValidator is not nil.
func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts *types.PartSet) {
if cs.privValidator == nil {
panic("entered createProposalBlock with privValidator being nil")
}
var commit *types.Commit
switch {
case cs.Height == 1:
@@ -1017,13 +1043,19 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts
case cs.LastCommit.HasTwoThirdsMajority():
// Make the commit from LastCommit
commit = cs.LastCommit.MakeCommit()
default:
// This shouldn't happen.
cs.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block.")
default: // This shouldn't happen.
cs.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block")
return
}
proposerAddr := cs.privValidator.GetPubKey().Address()
if cs.privValidatorPubKey == nil {
// If this node is a validator & proposer in the current round, it will
// miss the opportunity to create a block.
cs.Logger.Error(fmt.Sprintf("enterPropose: %v", errPubKeyIsNotSet))
return
}
proposerAddr := cs.privValidatorPubKey.Address()
return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr)
}
@@ -1411,7 +1443,8 @@ func (cs *ConsensusState) finalizeCommit(height int64) {
// restart).
endMsg := EndHeightMessage{height}
if err := cs.wal.WriteSync(endMsg); err != nil { // NOTE: fsync
panic(fmt.Sprintf("Failed to write %v msg to consensus wal due to %v. Check your FS and restart the node", endMsg, err))
panic(fmt.Sprintf("Failed to write %v msg to consensus wal due to %v. Check your FS and restart the node",
endMsg, err))
}
fail.Fail() // XXX
@@ -1445,6 +1478,11 @@ func (cs *ConsensusState) finalizeCommit(height int64) {
fail.Fail() // XXX
// Private validator might have changed it's key pair => refetch pubkey.
if err := cs.updatePrivValidatorPubKey(); err != nil {
cs.Logger.Error("Can't get private validator pubkey", "err", err)
}
// cs.StartTime is already set.
// Schedule Round0 to start soon.
cs.scheduleRound0(&cs.RoundState)
@@ -1458,8 +1496,22 @@ func (cs *ConsensusState) finalizeCommit(height int64) {
func (cs *ConsensusState) recordMetrics(height int64, block *types.Block) {
cs.metrics.Validators.Set(float64(cs.Validators.Size()))
cs.metrics.ValidatorsPower.Set(float64(cs.Validators.TotalVotingPower()))
missingValidators := 0
missingValidatorsPower := int64(0)
var (
missingValidators = 0
missingValidatorsPower int64
address types.Address
)
if cs.privValidator != nil {
if cs.privValidatorPubKey == nil {
// Metrics won't be updated, but it's not critical.
cs.Logger.Error(fmt.Sprintf("recordMetrics: %v", errPubKeyIsNotSet))
} else {
address = cs.privValidatorPubKey.Address()
}
}
for i, val := range cs.Validators.Validators {
var vote *types.CommitSig
if i < len(block.LastCommit.Precommits) {
@@ -1469,9 +1521,22 @@ func (cs *ConsensusState) recordMetrics(height int64, block *types.Block) {
missingValidators++
missingValidatorsPower += val.VotingPower
}
if bytes.Equal(val.Address, address) {
label := []string{
"validator_address", val.Address.String(),
}
cs.metrics.ValidatorPower.With(label...).Set(float64(val.VotingPower))
if vote != nil {
cs.metrics.ValidatorLastSignedHeight.With(label...).Set(float64(height))
} else {
cs.metrics.ValidatorMissedBlocks.With(label...).Add(float64(1))
}
}
}
cs.metrics.MissingValidators.Set(float64(missingValidators))
cs.metrics.MissingValidatorsPower.Set(float64(missingValidatorsPower))
cs.metrics.ByzantineValidators.Set(float64(len(block.Evidence.Evidence)))
byzantineValidatorsPower := int64(0)
for _, ev := range block.Evidence.Evidence {
@@ -1492,7 +1557,6 @@ func (cs *ConsensusState) recordMetrics(height int64, block *types.Block) {
cs.metrics.BlockSizeBytes.Set(float64(block.Size()))
cs.metrics.TotalTxs.Set(float64(block.TotalTxs))
cs.metrics.CommittedHeight.Set(float64(block.Height))
}
//-----------------------------------------------------------------------------
@@ -1613,16 +1677,15 @@ func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, err
if err == ErrVoteHeightMismatch {
return added, err
} else if voteErr, ok := err.(*types.ErrVoteConflictingVotes); ok {
addr := cs.privValidator.GetPubKey().Address()
if bytes.Equal(vote.ValidatorAddress, addr) {
if cs.privValidatorPubKey == nil {
return false, errPubKeyIsNotSet
}
if bytes.Equal(vote.ValidatorAddress, cs.privValidatorPubKey.Address()) {
cs.Logger.Error(
"Found conflicting vote from ourselves. Did you unsafe_reset a validator?",
"height",
vote.Height,
"round",
vote.Round,
"type",
vote.Type)
"height", vote.Height,
"round", vote.Round,
"type", vote.Type)
return added, err
}
cs.evpool.AddEvidence(voteErr.DuplicateVoteEvidence)
@@ -1647,14 +1710,10 @@ func (cs *ConsensusState) addVote(
peerID p2p.ID) (added bool, err error) {
cs.Logger.Debug(
"addVote",
"voteHeight",
vote.Height,
"voteType",
vote.Type,
"valIndex",
vote.ValidatorIndex,
"csHeight",
cs.Height)
"voteHeight", vote.Height,
"voteType", vote.Type,
"valIndex", vote.ValidatorIndex,
"csHeight", cs.Height)
// A precommit for the previous height?
// These come in while we wait timeoutCommit
@@ -1808,7 +1867,10 @@ func (cs *ConsensusState) signVote(
// and the privValidator will refuse to sign anything.
cs.wal.FlushAndSync()
addr := cs.privValidator.GetPubKey().Address()
if cs.privValidatorPubKey == nil {
return nil, errPubKeyIsNotSet
}
addr := cs.privValidatorPubKey.Address()
valIndex, _ := cs.Validators.GetByAddress(addr)
vote := &types.Vote{
@@ -1845,8 +1907,18 @@ func (cs *ConsensusState) voteTime() time.Time {
// sign the vote and publish on internalMsgQueue
func (cs *ConsensusState) signAddVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote {
// if we don't have a key or we're not in the validator set, do nothing
if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetPubKey().Address()) {
if cs.privValidator == nil { // the node does not have a key
return nil
}
if cs.privValidatorPubKey == nil {
// Vote won't be signed, but it's not critical.
cs.Logger.Error(fmt.Sprintf("signAddVote: %v", errPubKeyIsNotSet))
return nil
}
// If the node not in the validator set, do nothing.
if !cs.Validators.HasAddress(cs.privValidatorPubKey.Address()) {
return nil
}
vote, err := cs.signVote(type_, hash, header)
@@ -1861,6 +1933,18 @@ func (cs *ConsensusState) signAddVote(type_ types.SignedMsgType, hash []byte, he
return nil
}
// updatePrivValidatorPubKey get's the private validator public key and
// memoizes it. This func returns an error if the private validator is not
// responding or responds with an error.
func (cs *ConsensusState) updatePrivValidatorPubKey() error {
if cs.privValidator == nil {
return nil
}
cs.privValidatorPubKey = cs.privValidator.GetPubKey()
return nil
}
//---------------------------------------------------------
func CompareHRS(h1 int64, r1 int, s1 cstypes.RoundStepType, h2 int64, r2 int, s2 cstypes.RoundStepType) int {

View File

@@ -203,7 +203,9 @@ func (wal *baseWAL) WriteSync(msg WALMessage) error {
}
if err := wal.FlushAndSync(); err != nil {
wal.Logger.Error("WriteSync failed to flush consensus wal. WARNING: may result in creating alternative proposals / votes for the current height iff the node restarted",
wal.Logger.Error(
`WriteSync failed to flush consensus wal. WARNING: may result in creating alternative proposals / votes
for the current height iff the node restarted`,
"err", err)
return err
}

View File

@@ -8,7 +8,7 @@ import (
"io"
"math/big"
"golang.org/x/crypto/ripemd160"
"golang.org/x/crypto/ripemd160" // nolint
secp256k1 "github.com/btcsuite/btcd/btcec"

View File

@@ -1,5 +1,6 @@
module.exports = {
theme: "cosmos",
theme: 'cosmos',
title: 'Tendermint Core',
// locales: {
// "/": {
// lang: "en-US"
@@ -10,136 +11,161 @@ module.exports = {
// },
base: process.env.VUEPRESS_BASE,
themeConfig: {
docsRepo: "tendermint/tendermint",
repo: 'tendermint/tendermint',
docsRepo: 'tendermint/tendermint',
docsDir: 'docs',
editLinks: true,
docsDir: "docs",
logo: "/logo.svg",
label: "core",
gutter: {
title: "Help & Support",
editLink: true,
chat: {
title: "Riot Chat",
text: "Chat with Tendermint developers on Riot Chat.",
url: "https://riot.im/app/#/room/#tendermint:matrix.org",
bg: "#222"
},
forum: {
title: "Tendermint Forum",
text: "Join the Tendermint forum to learn more",
url: "https://forum.cosmos.network/c/tendermint",
bg: "#0B7E0B",
logo: "tendermint"
},
github: {
title: "Found an Issue?",
text: "Help us improve this page by suggesting edits on GitHub."
}
label: 'core',
algolia: {
id: "BH4D9OD16A",
key: "59f0e2deb984aa9cdf2b3a5fd24ac501",
index: "tendermint"
},
footer: {
logo: "/logo-bw.svg",
textLink: {
text: "tendermint.com",
url: "https://tendermint.com"
versions: [
{
"label": "v0.32",
"key": "v0.32"
},
services: [
{
"label": "v0.33",
"key": "v0.33"
},
{
"label": "v0.34",
"key": "v0.34"
},
{
"label": "master",
"key": "master"
}
],
topbar: {
banner: false,
},
sidebar: {
auto: true,
nav: [
{
service: "medium",
url: "https://medium.com/@tendermint"
},
{
service: "twitter",
url: "https://twitter.com/tendermint_team"
},
{
service: "linkedin",
url: "https://www.linkedin.com/company/tendermint/"
},
{
service: "reddit",
url: "https://reddit.com/r/cosmosnetwork"
},
{
service: "telegram",
url: "https://t.me/cosmosproject"
},
{
service: "youtube",
url: "https://www.youtube.com/c/CosmosProject"
}
],
smallprint:
"The development of the Tendermint project is led primarily by Tendermint Inc., the for-profit entity which also maintains this website. Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit.",
links: [
{
title: "Documentation",
title: 'Resources',
children: [
{
title: "Cosmos SDK",
url: "https://cosmos.network/docs"
title: 'Developer Sessions',
path: '/DEV_SESSIONS.html'
},
{
title: "Cosmos Hub",
url: "https://hub.cosmos.network/"
}
]
},
{
title: "Community",
children: [
{
title: "Tendermint blog",
url: "https://medium.com/@tendermint"
title: 'RPC',
path: 'https://docs.tendermint.com/master/rpc/',
static: true
},
{
title: "Forum",
url: "https://forum.cosmos.network/c/tendermint"
},
{
title: "Chat",
url: "https://riot.im/app/#/room/#tendermint:matrix.org"
}
]
},
{
title: "Contributing",
children: [
{
title: "Contributing to the docs",
url: "https://github.com/tendermint/tendermint"
},
{
title: "Source code on GitHub",
url: "https://github.com/tendermint/tendermint"
},
{
title: "Careers at Tendermint",
url: "https://tendermint.com/careers"
}
]
}
]
},
sidebar: [
gutter: {
title: 'Help & Support',
editLink: true,
forum: {
title: 'Tendermint Forum',
text: 'Join the Tendermint forum to learn more',
url: 'https://forum.cosmos.network/c/tendermint',
bg: '#0B7E0B',
logo: 'tendermint'
},
github: {
title: 'Found an Issue?',
text: 'Help us improve this page by suggesting edits on GitHub.'
}
},
footer: {
question: {
text: 'Chat with Tendermint developers in <a href=\'https://discord.gg/vcExX9T\' target=\'_blank\'>Discord</a> or reach out on the <a href=\'https://forum.cosmos.network/c/tendermint\' target=\'_blank\'>Tendermint Forum</a> to learn more.'
},
logo: '/logo-bw.svg',
textLink: {
text: 'tendermint.com',
url: 'https://tendermint.com'
},
services: [
{
service: 'medium',
url: 'https://medium.com/@tendermint'
},
{
service: 'twitter',
url: 'https://twitter.com/tendermint_team'
},
{
service: 'linkedin',
url: 'https://www.linkedin.com/company/tendermint/'
},
{
service: 'reddit',
url: 'https://reddit.com/r/cosmosnetwork'
},
{
service: 'telegram',
url: 'https://t.me/cosmosproject'
},
{
service: 'youtube',
url: 'https://www.youtube.com/c/CosmosProject'
}
],
smallprint:
'The development of Tendermint Core is led primarily by [Interchain GmbH](https://interchain.berlin/). Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit. The Tendermint trademark is owned by Tendermint Inc, the for-profit entity that also maintains this website.',
links: [
{
title: 'Documentation',
children: [
{
title: 'Cosmos SDK',
url: 'https://docs.cosmos.network'
},
{
title: 'Cosmos Hub',
url: 'https://hub.cosmos.network'
}
]
},
{
title: 'Community',
children: [
{
title: 'Tendermint blog',
url: 'https://medium.com/@tendermint'
},
{
title: 'Forum',
url: 'https://forum.cosmos.network/c/tendermint'
}
]
},
{
title: 'Contributing',
children: [
{
title: 'Contributing to the docs',
url: 'https://github.com/tendermint/tendermint'
},
{
title: 'Source code on GitHub',
url: 'https://github.com/tendermint/tendermint'
},
{
title: 'Careers at Tendermint',
url: 'https://tendermint.com/careers'
}
]
}
]
}
},
plugins: [
[
'@vuepress/google-analytics',
{
title: "Resources",
children: [
{
title: "Developer Sessions",
path: "/DEV_SESSIONS.html"
},
{
title: "RPC",
path: "/rpc/",
static: true
}
]
ga: 'UA-51029217-11'
}
]
},
markdown: {
anchor: {
permalinkSymbol: ""
}
}
]
};

7112
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"description": "Welcome to the Tendermint Core documentation!",
"main": "index.js",
"dependencies": {
"vuepress-theme-cosmos": "^1.0.54"
"vuepress-theme-cosmos": "^1.0.180"
},
"devDependencies": {},
"scripts": {

View File

@@ -18,34 +18,37 @@ Listen address can be changed in the config file (see
The following metrics are available:
| **Name** | **Type** | **Since** | **Tags** | **Description** |
| --------------------------------------- | --------- | --------- | -------------- | --------------------------------------------------------------- |
| consensus\_height | Gauge | 0.21.0 | | Height of the chain |
| consensus\_validators | Gauge | 0.21.0 | | Number of validators |
| consensus\_validators\_power | Gauge | 0.21.0 | | Total voting power of all validators |
| consensus\_missing\_validators | Gauge | 0.21.0 | | Number of validators who did not sign |
| consensus\_missing\_validators\_power | Gauge | 0.21.0 | | Total voting power of the missing validators |
| consensus\_byzantine\_validators | Gauge | 0.21.0 | | Number of validators who tried to double sign |
| consensus\_byzantine\_validators\_power | Gauge | 0.21.0 | | Total voting power of the byzantine validators |
| consensus\_block\_interval\_seconds | Histogram | 0.21.0 | | Time between this and last block (Block.Header.Time) in seconds |
| consensus\_rounds | Gauge | 0.21.0 | | Number of rounds |
| consensus\_num\_txs | Gauge | 0.21.0 | | Number of transactions |
| consensus\_block\_parts | counter | on dev | peer\_id | number of blockparts transmitted by peer |
| consensus\_latest\_block\_height | gauge | on dev | | /status sync\_info number |
| consensus\_fast\_syncing | gauge | on dev | | either 0 (not fast syncing) or 1 (syncing) |
| consensus\_total\_txs | Gauge | 0.21.0 | | Total number of transactions committed |
| consensus\_block\_size\_bytes | Gauge | 0.21.0 | | Block size in bytes |
| p2p\_peers | Gauge | 0.21.0 | | Number of peers node's connected to |
| p2p\_peer\_receive\_bytes\_total | counter | on dev | peer\_id, chID | number of bytes per channel received from a given peer |
| p2p\_peer\_send\_bytes\_total | counter | on dev | peer\_id, chID | number of bytes per channel sent to a given peer |
| p2p\_peer\_pending\_send\_bytes | gauge | on dev | peer\_id | number of pending bytes to be sent to a given peer |
| p2p\_num\_txs | gauge | on dev | peer\_id | number of transactions submitted by each peer\_id |
| p2p\_pending\_send\_bytes | gauge | on dev | peer\_id | amount of data pending to be sent to peer |
| mempool\_size | Gauge | 0.21.0 | | Number of uncommitted transactions |
| mempool\_tx\_size\_bytes | histogram | on dev | | transaction sizes in bytes |
| mempool\_failed\_txs | counter | on dev | | number of failed transactions |
| mempool\_recheck\_times | counter | on dev | | number of transactions rechecked in the mempool |
| state\_block\_processing\_time | histogram | on dev | | time between BeginBlock and EndBlock in ms |
| **Name** | **Type** | **Since** | **Tags** | **Description** |
| -------------------------------------- | --------- | --------- | ------------- | ---------------------------------------------------------------------- |
| consensus_height | Gauge | 0.21.0 | | Height of the chain |
| consensus_validators | Gauge | 0.21.0 | | Number of validators |
| consensus_validators_power | Gauge | 0.21.0 | | Total voting power of all validators |
| consensus_validator_power | Gauge | 0.33.0 | | Voting power of the node if in the validator set |
| consensus_validator_last_signed_height | Gauge | 0.33.0 | | Last height the node signed a block, if the node is a validator |
| consensus_validator_missed_blocks | Gauge | 0.33.0 | | Total amount of blocks missed for the node, if the node is a validator |
| consensus_missing_validators | Gauge | 0.21.0 | | Number of validators who did not sign |
| consensus_missing_validators_power | Gauge | 0.21.0 | | Total voting power of the missing validators |
| consensus_byzantine_validators | Gauge | 0.21.0 | | Number of validators who tried to double sign |
| consensus_byzantine_validators_power | Gauge | 0.21.0 | | Total voting power of the byzantine validators |
| consensus_block_interval_seconds | Histogram | 0.21.0 | | Time between this and last block (Block.Header.Time) in seconds |
| consensus_rounds | Gauge | 0.21.0 | | Number of rounds |
| consensus_num_txs | Gauge | 0.21.0 | | Number of transactions |
| consensus_total_txs | Gauge | 0.21.0 | | Total number of transactions committed |
| consensus_block_parts | counter | on dev | peer_id | number of blockparts transmitted by peer |
| consensus_latest_block_height | gauge | on dev | | /status sync_info number |
| consensus_fast_syncing | gauge | on dev | | either 0 (not fast syncing) or 1 (syncing) |
| consensus_block_size_bytes | Gauge | 0.21.0 | | Block size in bytes |
| p2p_peers | Gauge | 0.21.0 | | Number of peers node's connected to |
| p2p_peer_receive_bytes_total | counter | on dev | peer_id, chID | number of bytes per channel received from a given peer |
| p2p_peer_send_bytes_total | counter | on dev | peer_id, chID | number of bytes per channel sent to a given peer |
| p2p_peer_pending_send_bytes | gauge | on dev | peer_id | number of pending bytes to be sent to a given peer |
| p2p_num_txs | gauge | on dev | peer_id | number of transactions submitted by each peer_id |
| p2p_pending_send_bytes | gauge | on dev | peer_id | amount of data pending to be sent to peer |
| mempool_size | Gauge | 0.21.0 | | Number of uncommitted transactions |
| mempool_tx_size_bytes | histogram | on dev | | transaction sizes in bytes |
| mempool_failed_txs | counter | on dev | | number of failed transactions |
| mempool_recheck_times | counter | on dev | | number of transactions rechecked in the mempool |
| state_block_processing_time | histogram | on dev | | time between BeginBlock and EndBlock in ms |
## Useful queries

View File

@@ -34,7 +34,7 @@ func NewEvidenceReactor(evpool *EvidencePool) *EvidenceReactor {
evR := &EvidenceReactor{
evpool: evpool,
}
evR.BaseReactor = *p2p.NewBaseReactor("EvidenceReactor", evR)
evR.BaseReactor = *p2p.NewBaseReactor("Evidence", evR)
return evR
}
@@ -65,7 +65,7 @@ func (evR *EvidenceReactor) AddPeer(peer p2p.Peer) {
func (evR *EvidenceReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
msg, err := decodeMsg(msgBytes)
if err != nil {
evR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
evR.Logger.Error("Error decoding message", "src", src, "chId", chID, "err", err)
evR.Switch.StopPeerForError(src, err)
return
}

View File

@@ -60,10 +60,10 @@ func TestContains(t *testing.T) {
func BenchmarkCMapHas(b *testing.B) {
m := NewCMap()
for i := 0; i < 1000; i++ {
m.Set(string(i), i)
m.Set(fmt.Sprint(i), i)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Has(string(i))
m.Has(fmt.Sprint(i))
}
}

View File

@@ -39,6 +39,7 @@ import (
"sync"
"github.com/pkg/errors"
cmn "github.com/tendermint/tendermint/libs/common"
)

View File

@@ -382,7 +382,7 @@ func benchmarkNClients(n int, b *testing.B) {
s.PublishWithEvents(
ctx,
"Gamora",
map[string][]string{"abci.Account.Owner": {"Ivan"}, "abci.Invoices.Number": {string(i)}},
map[string][]string{"abci.Account.Owner": {"Ivan"}, "abci.Invoices.Number": {fmt.Sprint(i)}},
)
}
}

View File

@@ -678,9 +678,9 @@ func (cache *mapTxCache) Push(tx types.Tx) bool {
if cache.list.Len() >= cache.size {
popped := cache.list.Front()
poppedTxHash := popped.Value.([sha256.Size]byte)
delete(cache.map_, poppedTxHash)
if popped != nil {
poppedTxHash := popped.Value.([sha256.Size]byte)
delete(cache.map_, poppedTxHash)
cache.list.Remove(popped)
}
}

View File

@@ -47,7 +47,7 @@ type mempoolIDs struct {
activeIDs map[uint16]struct{} // used to check if a given peerID key is used, the value doesn't matter
}
// Reserve searches for the next unused ID and assignes it to the
// Reserve searches for the next unused ID and assigns it to the
// peer.
func (ids *mempoolIDs) ReserveForPeer(peer p2p.Peer) {
ids.mtx.Lock()
@@ -110,10 +110,16 @@ func NewReactor(config *cfg.MempoolConfig, mempool *CListMempool) *Reactor {
mempool: mempool,
ids: newMempoolIDs(),
}
memR.BaseReactor = *p2p.NewBaseReactor("Reactor", memR)
memR.BaseReactor = *p2p.NewBaseReactor("Mempool", memR)
return memR
}
// InitPeer implements Reactor by creating a state for the peer.
func (memR *Reactor) InitPeer(peer p2p.Peer) p2p.Peer {
memR.ids.ReserveForPeer(peer)
return peer
}
// SetLogger sets the Logger on the reactor and the underlying mempool.
func (memR *Reactor) SetLogger(l log.Logger) {
memR.Logger = l
@@ -142,7 +148,6 @@ func (memR *Reactor) GetChannels() []*p2p.ChannelDescriptor {
// AddPeer implements Reactor.
// It starts a broadcast routine ensuring all txs are forwarded to the given peer.
func (memR *Reactor) AddPeer(peer p2p.Peer) {
memR.ids.ReserveForPeer(peer)
go memR.broadcastTxRoutine(peer)
}
@@ -157,7 +162,7 @@ func (memR *Reactor) RemovePeer(peer p2p.Peer, reason interface{}) {
func (memR *Reactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
msg, err := memR.decodeMsg(msgBytes)
if err != nil {
memR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
memR.Logger.Error("Error decoding message", "src", src, "chId", chID, "err", err)
memR.Switch.StopPeerForError(src, err)
return
}

View File

@@ -223,3 +223,21 @@ func TestMempoolIDsPanicsIfNodeRequestsOvermaxActiveIDs(t *testing.T) {
ids.ReserveForPeer(peer)
})
}
func TestDontExhaustMaxActiveIDs(t *testing.T) {
config := cfg.TestConfig()
const N = 1
reactors := makeAndConnectReactors(config, N)
defer func() {
for _, r := range reactors {
r.Stop()
}
}()
reactor := reactors[0]
for i := 0; i < maxActiveIDs+1; i++ {
peer := mock.NewPeer(nil)
reactor.Receive(MempoolChannel, peer, []byte{0x1, 0x2, 0x3})
reactor.AddPeer(peer)
}
}

View File

@@ -467,6 +467,11 @@ func createTransport(
}
p2p.MultiplexTransportConnFilters(connFilters...)(transport)
// Limit the number of incoming connections.
max := config.P2P.MaxNumInboundPeers
p2p.MultiplexTransportMaxIncomingConnections(max)(transport)
return transport, peerFilters
}
@@ -1187,7 +1192,19 @@ func createAndStartPrivValidatorSocketClient(
return nil, errors.Wrap(err, "failed to start private validator")
}
return pvsc, nil
// try to get a pubkey from private validate first time
pubKey := pvsc.GetPubKey()
if pubKey == nil {
return nil, errors.New("could not retrieve public key from private validator")
}
const (
retries = 50 // 50 * 100ms = 5s total
timeout = 100 * time.Millisecond
)
pvscWithRetries := privval.NewRetrySignerClient(pvsc, retries, timeout)
return pvscWithRetries, nil
}
// splitAndTrimEmpty slices s into all subslices separated by sep and returns a

View File

@@ -158,7 +158,7 @@ func TestNodeSetPrivValTCP(t *testing.T) {
n, err := DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
assert.IsType(t, &privval.SignerClient{}, n.PrivValidator())
assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
}
// address without a protocol must result in error
@@ -202,7 +202,7 @@ func TestNodeSetPrivValIPC(t *testing.T) {
n, err := DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
assert.IsType(t, &privval.SignerClient{}, n.PrivValidator())
assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
}
// testFreeAddr claims a free port so we don't block on listener being ready.

View File

@@ -380,7 +380,7 @@ func deriveSecretAndChallenge(
copy(recvSecret[:], res[aeadKeySize:aeadKeySize*2])
}
return
return recvSecret, sendSecret, challenge
}
// computeDHSecret computes a Diffie-Hellman shared secret key

View File

@@ -313,21 +313,43 @@ var rfc4862 = net.IPNet{IP: net.ParseIP("FE80::"), Mask: net.CIDRMask(64, 128)}
var rfc6052 = net.IPNet{IP: net.ParseIP("64:FF9B::"), Mask: net.CIDRMask(96, 128)}
var rfc6145 = net.IPNet{IP: net.ParseIP("::FFFF:0:0:0"), Mask: net.CIDRMask(96, 128)}
var zero4 = net.IPNet{IP: net.ParseIP("0.0.0.0"), Mask: net.CIDRMask(8, 32)}
var (
// onionCatNet defines the IPv6 address block used to support Tor.
// bitcoind encodes a .onion address as a 16 byte number by decoding the
// address prior to the .onion (i.e. the key hash) base32 into a ten
// byte number. It then stores the first 6 bytes of the address as
// 0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43.
//
// This is the same range used by OnionCat, which is part part of the
// RFC4193 unique local IPv6 range.
//
// In summary the format is:
// { magic 6 bytes, 10 bytes base32 decode of key hash }
onionCatNet = ipNet("fd87:d87e:eb43::", 48, 128)
)
// ipNet returns a net.IPNet struct given the passed IP address string, number
// of one bits to include at the start of the mask, and the total number of bits
// for the mask.
func ipNet(ip string, ones, bits int) net.IPNet {
return net.IPNet{IP: net.ParseIP(ip), Mask: net.CIDRMask(ones, bits)}
}
func (na *NetAddress) RFC1918() bool {
return rfc1918_10.Contains(na.IP) ||
rfc1918_192.Contains(na.IP) ||
rfc1918_172.Contains(na.IP)
}
func (na *NetAddress) RFC3849() bool { return rfc3849.Contains(na.IP) }
func (na *NetAddress) RFC3927() bool { return rfc3927.Contains(na.IP) }
func (na *NetAddress) RFC3964() bool { return rfc3964.Contains(na.IP) }
func (na *NetAddress) RFC4193() bool { return rfc4193.Contains(na.IP) }
func (na *NetAddress) RFC4380() bool { return rfc4380.Contains(na.IP) }
func (na *NetAddress) RFC4843() bool { return rfc4843.Contains(na.IP) }
func (na *NetAddress) RFC4862() bool { return rfc4862.Contains(na.IP) }
func (na *NetAddress) RFC6052() bool { return rfc6052.Contains(na.IP) }
func (na *NetAddress) RFC6145() bool { return rfc6145.Contains(na.IP) }
func (na *NetAddress) RFC3849() bool { return rfc3849.Contains(na.IP) }
func (na *NetAddress) RFC3927() bool { return rfc3927.Contains(na.IP) }
func (na *NetAddress) RFC3964() bool { return rfc3964.Contains(na.IP) }
func (na *NetAddress) RFC4193() bool { return rfc4193.Contains(na.IP) }
func (na *NetAddress) RFC4380() bool { return rfc4380.Contains(na.IP) }
func (na *NetAddress) RFC4843() bool { return rfc4843.Contains(na.IP) }
func (na *NetAddress) RFC4862() bool { return rfc4862.Contains(na.IP) }
func (na *NetAddress) RFC6052() bool { return rfc6052.Contains(na.IP) }
func (na *NetAddress) RFC6145() bool { return rfc6145.Contains(na.IP) }
func (na *NetAddress) OnionCatTor() bool { return onionCatNet.Contains(na.IP) }
func removeProtocolIfDefined(addr string) string {
if strings.Contains(addr, "://") {

View File

@@ -768,31 +768,36 @@ func (a *addrBook) calcOldBucket(addr *p2p.NetAddress) int {
}
// Return a string representing the network group of this address.
// This is the /16 for IPv4, the /32 (/36 for he.net) for IPv6, the string
// This is the /16 for IPv4 (e.g. 1.2.0.0), the /32 (/36 for he.net) for IPv6, the string
// "local" for a local address and the string "unroutable" for an unroutable
// address.
func (a *addrBook) groupKey(na *p2p.NetAddress) string {
if a.routabilityStrict && na.Local() {
return groupKeyFor(na, a.routabilityStrict)
}
func groupKeyFor(na *p2p.NetAddress, routabilityStrict bool) string {
if routabilityStrict && na.Local() {
return "local"
}
if a.routabilityStrict && !na.Routable() {
if routabilityStrict && !na.Routable() {
return "unroutable"
}
if ipv4 := na.IP.To4(); ipv4 != nil {
return (&net.IPNet{IP: na.IP, Mask: net.CIDRMask(16, 32)}).String()
return na.IP.Mask(net.CIDRMask(16, 32)).String()
}
if na.RFC6145() || na.RFC6052() {
// last four bytes are the ip address
ip := na.IP[12:16]
return (&net.IPNet{IP: ip, Mask: net.CIDRMask(16, 32)}).String()
return ip.Mask(net.CIDRMask(16, 32)).String()
}
if na.RFC3964() {
ip := na.IP[2:7]
return (&net.IPNet{IP: ip, Mask: net.CIDRMask(16, 32)}).String()
ip := na.IP[2:6]
return ip.Mask(net.CIDRMask(16, 32)).String()
}
if na.RFC4380() {
// teredo tunnels have the last 4 bytes as the v4 address XOR
// 0xff.
@@ -800,20 +805,24 @@ func (a *addrBook) groupKey(na *p2p.NetAddress) string {
for i, byte := range na.IP[12:16] {
ip[i] = byte ^ 0xff
}
return (&net.IPNet{IP: ip, Mask: net.CIDRMask(16, 32)}).String()
return ip.Mask(net.CIDRMask(16, 32)).String()
}
if na.OnionCatTor() {
// group is keyed off the first 4 bits of the actual onion key.
return fmt.Sprintf("tor:%d", na.IP[6]&((1<<4)-1))
}
// OK, so now we know ourselves to be a IPv6 address.
// bitcoind uses /32 for everything, except for Hurricane Electric's
// (he.net) IP range, which it uses /36 for.
bits := 32
heNet := &net.IPNet{IP: net.ParseIP("2001:470::"),
Mask: net.CIDRMask(32, 128)}
heNet := &net.IPNet{IP: net.ParseIP("2001:470::"), Mask: net.CIDRMask(32, 128)}
if heNet.Contains(na.IP) {
bits = 36
}
return (&net.IPNet{IP: na.IP, Mask: net.CIDRMask(bits, 128)}).String()
ipv6Mask := net.CIDRMask(bits, 128)
return na.IP.Mask(ipv6Mask).String()
}
// doubleSha256 calculates sha256(sha256(b)) and returns the resulting bytes.

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"math"
"net"
"os"
"testing"
@@ -545,6 +546,73 @@ func TestMultipleAddrBookAddressSelection(t *testing.T) {
}
}
func TestAddrBookGroupKey(t *testing.T) {
// non-strict routability
testCases := []struct {
name string
ip string
expKey string
}{
// IPv4 normal.
{"ipv4 normal class a", "12.1.2.3", "12.1.0.0"},
{"ipv4 normal class b", "173.1.2.3", "173.1.0.0"},
{"ipv4 normal class c", "196.1.2.3", "196.1.0.0"},
// IPv6/IPv4 translations.
{"ipv6 rfc3964 with ipv4 encap", "2002:0c01:0203::", "12.1.0.0"},
{"ipv6 rfc4380 toredo ipv4", "2001:0:1234::f3fe:fdfc", "12.1.0.0"},
{"ipv6 rfc6052 well-known prefix with ipv4", "64:ff9b::0c01:0203", "12.1.0.0"},
{"ipv6 rfc6145 translated ipv4", "::ffff:0:0c01:0203", "12.1.0.0"},
// Tor.
{"ipv6 tor onioncat", "fd87:d87e:eb43:1234::5678", "tor:2"},
{"ipv6 tor onioncat 2", "fd87:d87e:eb43:1245::6789", "tor:2"},
{"ipv6 tor onioncat 3", "fd87:d87e:eb43:1345::6789", "tor:3"},
// IPv6 normal.
{"ipv6 normal", "2602:100::1", "2602:100::"},
{"ipv6 normal 2", "2602:0100::1234", "2602:100::"},
{"ipv6 hurricane electric", "2001:470:1f10:a1::2", "2001:470:1000::"},
{"ipv6 hurricane electric 2", "2001:0470:1f10:a1::2", "2001:470:1000::"},
}
for i, tc := range testCases {
nip := net.ParseIP(tc.ip)
key := groupKeyFor(p2p.NewNetAddressIPPort(nip, 26656), false)
assert.Equal(t, tc.expKey, key, "#%d", i)
}
// strict routability
testCases = []struct {
name string
ip string
expKey string
}{
// Local addresses.
{"ipv4 localhost", "127.0.0.1", "local"},
{"ipv6 localhost", "::1", "local"},
{"ipv4 zero", "0.0.0.0", "local"},
{"ipv4 first octet zero", "0.1.2.3", "local"},
// Unroutable addresses.
{"ipv4 invalid bcast", "255.255.255.255", "unroutable"},
{"ipv4 rfc1918 10/8", "10.1.2.3", "unroutable"},
{"ipv4 rfc1918 172.16/12", "172.16.1.2", "unroutable"},
{"ipv4 rfc1918 192.168/16", "192.168.1.2", "unroutable"},
{"ipv6 rfc3849 2001:db8::/32", "2001:db8::1234", "unroutable"},
{"ipv4 rfc3927 169.254/16", "169.254.1.2", "unroutable"},
{"ipv6 rfc4193 fc00::/7", "fc00::1234", "unroutable"},
{"ipv6 rfc4843 2001:10::/28", "2001:10::1234", "unroutable"},
{"ipv6 rfc4862 fe80::/64", "fe80::1234", "unroutable"},
}
for i, tc := range testCases {
nip := net.ParseIP(tc.ip)
key := groupKeyFor(p2p.NewNetAddressIPPort(nip, 26656), true)
assert.Equal(t, tc.expKey, key, "#%d", i)
}
}
func assertMOldAndNNewAddrsInSelection(t *testing.T, m, n int, addrs []*p2p.NetAddress, book *addrBook) {
nOld, nNew := countOldAndNewAddrsInSelection(addrs, book)
assert.Equal(t, m, nOld, "old addresses")

View File

@@ -130,7 +130,7 @@ func NewPEXReactor(b AddrBook, config *PEXReactorConfig) *PEXReactor {
lastReceivedRequests: cmn.NewCMap(),
crawlPeerInfos: make(map[p2p.ID]crawlPeerInfo),
}
r.BaseReactor = *p2p.NewBaseReactor("PEXReactor", r)
r.BaseReactor = *p2p.NewBaseReactor("PEX", r)
return r
}
@@ -227,7 +227,7 @@ func (r *PEXReactor) logErrAddrBook(err error) {
func (r *PEXReactor) Receive(chID byte, src Peer, msgBytes []byte) {
msg, err := decodeMsg(msgBytes)
if err != nil {
r.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
r.Logger.Error("Error decoding message", "src", src, "chId", chID, "err", err)
r.Switch.StopPeerForError(src, err)
return
}

View File

@@ -7,6 +7,7 @@ import (
"time"
"github.com/pkg/errors"
"golang.org/x/net/netutil"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/p2p/conn"
@@ -122,11 +123,18 @@ func MultiplexTransportResolver(resolver IPResolver) MultiplexTransportOption {
return func(mt *MultiplexTransport) { mt.resolver = resolver }
}
// MultiplexTransportMaxIncomingConnections sets the maximum number of
// simultaneous connections (incoming). Default: 0 (unlimited)
func MultiplexTransportMaxIncomingConnections(n int) MultiplexTransportOption {
return func(mt *MultiplexTransport) { mt.maxIncomingConnections = n }
}
// MultiplexTransport accepts and dials tcp connections and upgrades them to
// multiplexed peers.
type MultiplexTransport struct {
netAddr NetAddress
listener net.Listener
netAddr NetAddress
listener net.Listener
maxIncomingConnections int // see MaxIncomingConnections
acceptc chan accept
closec chan struct{}
@@ -240,6 +248,10 @@ func (mt *MultiplexTransport) Listen(addr NetAddress) error {
return err
}
if mt.maxIncomingConnections > 0 {
ln = netutil.LimitListener(ln, mt.maxIncomingConnections)
}
mt.netAddr = addr
mt.listener = ln

View File

@@ -5,6 +5,7 @@ import (
"math/rand"
"net"
"reflect"
"strings"
"testing"
"time"
@@ -134,6 +135,50 @@ func TestTransportMultiplexConnFilterTimeout(t *testing.T) {
}
}
func TestTransportMultiplexMaxIncomingConnections(t *testing.T) {
mt := newMultiplexTransport(
emptyNodeInfo(),
NodeKey{
PrivKey: ed25519.GenPrivKey(),
},
)
id := mt.nodeKey.ID()
MultiplexTransportMaxIncomingConnections(0)(mt)
addr, err := NewNetAddressString(IDAddressString(id, "127.0.0.1:0"))
if err != nil {
t.Fatal(err)
}
if err := mt.Listen(*addr); err != nil {
t.Fatal(err)
}
errc := make(chan error)
go func() {
addr := NewNetAddress(id, mt.listener.Addr())
_, err := addr.Dial()
if err != nil {
errc <- err
return
}
close(errc)
}()
if err := <-errc; err != nil {
t.Errorf("connection failed: %v", err)
}
_, err = mt.Accept(peerConfig{})
if err == nil || !strings.Contains(err.Error(), "connection reset by peer") {
t.Errorf("expected connection reset by peer error, got %v", err)
}
}
func TestTransportMultiplexAcceptMultiple(t *testing.T) {
mt := testSetupMultiplexTransport(t)
laddr := NewNetAddress(mt.nodeKey.ID(), mt.listener.Addr())
@@ -210,6 +255,7 @@ func testDialer(dialAddr NetAddress, errc chan error) {
}
func TestTransportMultiplexAcceptNonBlocking(t *testing.T) {
t.Skip("")
mt := testSetupMultiplexTransport(t)
var (

View File

@@ -209,7 +209,7 @@ func getServiceURL(rootURL string) (url, urnDomain string, err error) {
defer r.Body.Close() // nolint: errcheck
if r.StatusCode >= 400 {
err = errors.New(string(r.StatusCode))
err = errors.New(fmt.Sprint(r.StatusCode))
return
}
var root Root
@@ -378,7 +378,7 @@ func (n *upnpNAT) AddPortMapping(
// fmt.Println(string(body), err)
mappedExternalPort = externalPort
_ = response
return
return mappedExternalPort, err
}
func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) {

View File

@@ -1,9 +1,11 @@
package privval
import (
"errors"
"fmt"
)
// EndpointTimeoutError occurs when endpoint times out.
type EndpointTimeoutError struct{}
// Implement the net.Error interface.
@@ -13,15 +15,15 @@ func (e EndpointTimeoutError) Temporary() bool { return true }
// Socket errors.
var (
ErrUnexpectedResponse = fmt.Errorf("received unexpected response")
ErrNoConnection = fmt.Errorf("endpoint is not connected")
ErrConnectionTimeout = EndpointTimeoutError{}
ErrReadTimeout = fmt.Errorf("endpoint read timed out")
ErrWriteTimeout = fmt.Errorf("endpoint write timed out")
ErrNoConnection = errors.New("endpoint is not connected")
ErrReadTimeout = errors.New("endpoint read timed out")
ErrUnexpectedResponse = errors.New("empty response")
ErrWriteTimeout = errors.New("endpoint write timed out")
)
// RemoteSignerError allows (remote) validators to include meaningful error descriptions in their reply.
// RemoteSignerError allows (remote) validators to include meaningful error
// descriptions in their reply.
type RemoteSignerError struct {
// TODO(ismail): create an enum of known errors
Code int

View File

@@ -0,0 +1,85 @@
package privval
import (
"errors"
"time"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/types"
)
// RetrySignerClient wraps SignerClient adding retry for each operation (except
// Ping) w/ a timeout.
type RetrySignerClient struct {
next *SignerClient
retries int
timeout time.Duration
}
// NewRetrySignerClient returns RetrySignerClient. If +retries+ is 0, the
// client will be retrying each operation indefinitely.
func NewRetrySignerClient(sc *SignerClient, retries int, timeout time.Duration) *RetrySignerClient {
return &RetrySignerClient{sc, retries, timeout}
}
var _ types.PrivValidator = (*RetrySignerClient)(nil)
func (sc *RetrySignerClient) Close() error {
return sc.next.Close()
}
func (sc *RetrySignerClient) IsConnected() bool {
return sc.next.IsConnected()
}
func (sc *RetrySignerClient) WaitForConnection(maxWait time.Duration) error {
return sc.next.WaitForConnection(maxWait)
}
//--------------------------------------------------------
// Implement PrivValidator
func (sc *RetrySignerClient) Ping() error {
return sc.next.Ping()
}
func (sc *RetrySignerClient) GetPubKey() crypto.PubKey {
for i := 0; i < sc.retries || sc.retries == 0; i++ {
pk := sc.next.GetPubKey()
if pk != nil {
return pk
}
time.Sleep(sc.timeout)
}
return nil
}
func (sc *RetrySignerClient) SignVote(chainID string, vote *types.Vote) error {
for i := 0; i < sc.retries || sc.retries == 0; i++ {
err := sc.next.SignVote(chainID, vote)
if err == nil {
return nil
}
// If remote signer errors, we don't retry.
if _, ok := err.(*RemoteSignerError); ok {
return err
}
time.Sleep(sc.timeout)
}
return errors.New("exhausted all attempts to sign vote")
}
func (sc *RetrySignerClient) SignProposal(chainID string, proposal *types.Proposal) error {
for i := 0; i < sc.retries || sc.retries == 0; i++ {
err := sc.next.SignProposal(chainID, proposal)
if err == nil {
return nil
}
// If remote signer errors, we don't retry.
if _, ok := err.(*RemoteSignerError); ok {
return err
}
time.Sleep(sc.timeout)
}
return errors.New("exhausted all attempts to sign proposal")
}

View File

@@ -50,7 +50,6 @@ func (sc *SignerClient) WaitForConnection(maxWait time.Duration) error {
// Ping sends a ping request to the remote signer
func (sc *SignerClient) Ping() error {
response, err := sc.endpoint.SendRequest(&PingRequest{})
if err != nil {
sc.endpoint.Logger.Error("SignerClient::Ping", "err", err)
return nil
@@ -58,7 +57,6 @@ func (sc *SignerClient) Ping() error {
_, ok := response.(*PingResponse)
if !ok {
sc.endpoint.Logger.Error("SignerClient::Ping", "err", "response != PingResponse")
return err
}
@@ -91,16 +89,13 @@ func (sc *SignerClient) GetPubKey() crypto.PubKey {
func (sc *SignerClient) SignVote(chainID string, vote *types.Vote) error {
response, err := sc.endpoint.SendRequest(&SignVoteRequest{Vote: vote})
if err != nil {
sc.endpoint.Logger.Error("SignerClient::SignVote", "err", err)
return err
}
resp, ok := response.(*SignedVoteResponse)
if !ok {
sc.endpoint.Logger.Error("SignerClient::GetPubKey", "err", "response != SignedVoteResponse")
return ErrUnexpectedResponse
}
if resp.Error != nil {
return resp.Error
}
@@ -113,13 +108,11 @@ func (sc *SignerClient) SignVote(chainID string, vote *types.Vote) error {
func (sc *SignerClient) SignProposal(chainID string, proposal *types.Proposal) error {
response, err := sc.endpoint.SendRequest(&SignProposalRequest{Proposal: proposal})
if err != nil {
sc.endpoint.Logger.Error("SignerClient::SignProposal", "err", err)
return err
}
resp, ok := response.(*SignedProposalResponse)
if !ok {
sc.endpoint.Logger.Error("SignerClient::SignProposal", "err", "response != SignedProposalResponse")
return ErrUnexpectedResponse
}
if resp.Error != nil {

View File

@@ -250,8 +250,7 @@ func TestSignerUnexpectedResponse(t *testing.T) {
ts := time.Now()
want := &types.Vote{Timestamp: ts, Type: types.PrecommitType}
e := tc.signerClient.SignVote(tc.chainID, want)
assert.EqualError(t, e, "received unexpected response")
assert.EqualError(t, e, "empty response")
}
}

View File

@@ -15,24 +15,26 @@ const (
// SignerServiceEndpointOption sets an optional parameter on the SignerDialerEndpoint.
type SignerServiceEndpointOption func(*SignerDialerEndpoint)
// SignerDialerEndpointTimeoutReadWrite sets the read and write timeout for connections
// from external signing processes.
// SignerDialerEndpointTimeoutReadWrite sets the read and write timeout for
// connections from client processes.
func SignerDialerEndpointTimeoutReadWrite(timeout time.Duration) SignerServiceEndpointOption {
return func(ss *SignerDialerEndpoint) { ss.timeoutReadWrite = timeout }
}
// SignerDialerEndpointConnRetries sets the amount of attempted retries to acceptNewConnection.
// SignerDialerEndpointConnRetries sets the amount of attempted retries to
// acceptNewConnection.
func SignerDialerEndpointConnRetries(retries int) SignerServiceEndpointOption {
return func(ss *SignerDialerEndpoint) { ss.maxConnRetries = retries }
}
// SignerDialerEndpointRetryWaitInterval sets the retry wait interval to a custom value
// SignerDialerEndpointRetryWaitInterval sets the retry wait interval to a
// custom value.
func SignerDialerEndpointRetryWaitInterval(interval time.Duration) SignerServiceEndpointOption {
return func(ss *SignerDialerEndpoint) { ss.retryWait = interval }
}
// SignerDialerEndpoint dials using its dialer and responds to any
// signature requests using its privVal.
// SignerDialerEndpoint dials using its dialer and responds to any signature
// requests using its privVal.
type SignerDialerEndpoint struct {
signerEndpoint

View File

@@ -12,7 +12,7 @@ import (
)
const (
defaultTimeoutReadWriteSeconds = 3
defaultTimeoutReadWriteSeconds = 5
)
type signerEndpoint struct {

View File

@@ -10,11 +10,22 @@ import (
"github.com/tendermint/tendermint/libs/log"
)
// SignerValidatorEndpointOption sets an optional parameter on the SocketVal.
type SignerValidatorEndpointOption func(*SignerListenerEndpoint)
// SignerListenerEndpointOption sets an optional parameter on the SignerListenerEndpoint.
type SignerListenerEndpointOption func(*SignerListenerEndpoint)
// SignerListenerEndpoint listens for an external process to dial in
// and keeps the connection alive by dropping and reconnecting
// SignerListenerEndpointTimeoutReadWrite sets the read and write timeout for
// connections from external signing processes.
//
// Default: 5s
func SignerListenerEndpointTimeoutReadWrite(timeout time.Duration) SignerListenerEndpointOption {
return func(sl *SignerListenerEndpoint) { sl.signerEndpoint.timeoutReadWrite = timeout }
}
// SignerListenerEndpoint listens for an external process to dial in and keeps
// the connection alive by dropping and reconnecting.
//
// The process will send pings every ~3s (read/write timeout * 2/3) to keep the
// connection alive.
type SignerListenerEndpoint struct {
signerEndpoint
@@ -24,6 +35,7 @@ type SignerListenerEndpoint struct {
timeoutAccept time.Duration
pingTimer *time.Ticker
pingInterval time.Duration
instanceMtx sync.Mutex // Ensures instance public methods access, i.e. SendRequest
}
@@ -32,15 +44,21 @@ type SignerListenerEndpoint struct {
func NewSignerListenerEndpoint(
logger log.Logger,
listener net.Listener,
options ...SignerListenerEndpointOption,
) *SignerListenerEndpoint {
sc := &SignerListenerEndpoint{
sl := &SignerListenerEndpoint{
listener: listener,
timeoutAccept: defaultTimeoutAcceptSeconds * time.Second,
}
sc.BaseService = *cmn.NewBaseService(logger, "SignerListenerEndpoint", sc)
sc.signerEndpoint.timeoutReadWrite = defaultTimeoutReadWriteSeconds * time.Second
return sc
sl.BaseService = *cmn.NewBaseService(logger, "SignerListenerEndpoint", sl)
sl.signerEndpoint.timeoutReadWrite = defaultTimeoutReadWriteSeconds * time.Second
for _, optionFunc := range options {
optionFunc(sl)
}
return sl
}
// OnStart implements cmn.Service.
@@ -48,7 +66,9 @@ func (sl *SignerListenerEndpoint) OnStart() error {
sl.connectRequestCh = make(chan struct{})
sl.connectionAvailableCh = make(chan net.Conn)
sl.pingTimer = time.NewTicker(defaultPingPeriodMilliseconds * time.Millisecond)
// NOTE: ping timeout must be less than read/write timeout
sl.pingInterval = time.Duration(sl.signerEndpoint.timeoutReadWrite.Milliseconds()*2/3) * time.Millisecond
sl.pingTimer = time.NewTicker(sl.pingInterval)
go sl.serviceLoop()
go sl.pingLoop()
@@ -116,6 +136,7 @@ func (sl *SignerListenerEndpoint) ensureConnection(maxWait time.Duration) error
}
// block until connected or timeout
sl.Logger.Info("SignerListener: Blocking for connection")
sl.triggerConnect()
err := sl.WaitConnection(sl.connectionAvailableCh, maxWait)
if err != nil {

View File

@@ -155,7 +155,11 @@ func newSignerListenerEndpoint(logger log.Logger, addr string, timeoutReadWrite
listener = tcpLn
}
return NewSignerListenerEndpoint(logger, listener)
return NewSignerListenerEndpoint(
logger,
listener,
SignerListenerEndpointTimeoutReadWrite(testTimeoutReadWrite),
)
}
func startListenerEndpointAsync(t *testing.T, sle *SignerListenerEndpoint, endpointIsOpenCh chan struct{}) {

View File

@@ -9,8 +9,7 @@ import (
)
const (
defaultTimeoutAcceptSeconds = 3
defaultPingPeriodMilliseconds = 100
defaultTimeoutAcceptSeconds = 3
)
// timeoutError can be used to check if an error returned from the netp package

View File

@@ -28,6 +28,55 @@ const (
protoTCP = "tcp"
)
// Parsed URL structure
type parsedURL struct {
url.URL
}
// Parse URL and set defaults
func newParsedURL(remoteAddr string) (*parsedURL, error) {
u, err := url.Parse(remoteAddr)
if err != nil {
return nil, err
}
// default to tcp if nothing specified
if u.Scheme == "" {
u.Scheme = protoTCP
}
return &parsedURL{*u}, nil
}
// Change protocol to HTTP for unknown protocols and TCP protocol - useful for RPC connections
func (u *parsedURL) SetDefaultSchemeHTTP() {
// protocol to use for http operations, to support both http and https
switch u.Scheme {
case protoHTTP, protoHTTPS, protoWS, protoWSS:
// known protocols not changed
default:
// default to http for unknown protocols (ex. tcp)
u.Scheme = protoHTTP
}
}
// Get full address without the protocol - useful for Dialer connections
func (u parsedURL) GetHostWithPath() string {
// Remove protocol, userinfo and # fragment, assume opaque is empty
return u.Host + u.EscapedPath()
}
// Get a trimmed address - useful for WS connections
func (u parsedURL) GetTrimmedHostWithPath() string {
// replace / with . for http requests (kvstore domain)
return strings.Replace(u.GetHostWithPath(), "/", ".", -1)
}
// Get a trimmed address with protocol - useful as address in RPC connections
func (u parsedURL) GetTrimmedURL() string {
return u.Scheme + "://" + u.GetTrimmedHostWithPath()
}
// HTTPClient is a common interface for JSONRPCClient and URIClient.
type HTTPClient interface {
Call(method string, params map[string]interface{}, result interface{}) (interface{}, error)
@@ -35,62 +84,6 @@ type HTTPClient interface {
SetCodec(*amino.Codec)
}
// protocol - client's protocol (for example, "http", "https", "wss", "ws", "tcp")
// trimmedS - rest of the address (for example, "192.0.2.1:25", "[2001:db8::1]:80") with "/" replaced with "."
func toClientAddrAndParse(remoteAddr string) (network string, trimmedS string, err error) {
protocol, address, err := parseRemoteAddr(remoteAddr)
if err != nil {
return "", "", err
}
// protocol to use for http operations, to support both http and https
var clientProtocol string
// default to http for unknown protocols (ex. tcp)
switch protocol {
case protoHTTP, protoHTTPS, protoWS, protoWSS:
clientProtocol = protocol
default:
clientProtocol = protoHTTP
}
// replace / with . for http requests (kvstore domain)
trimmedAddress := strings.Replace(address, "/", ".", -1)
return clientProtocol, trimmedAddress, nil
}
func toClientAddress(remoteAddr string) (string, error) {
clientProtocol, trimmedAddress, err := toClientAddrAndParse(remoteAddr)
if err != nil {
return "", err
}
return clientProtocol + "://" + trimmedAddress, nil
}
// network - name of the network (for example, "tcp", "unix")
// s - rest of the address (for example, "192.0.2.1:25", "[2001:db8::1]:80")
// TODO: Deprecate support for IP:PORT or /path/to/socket
func parseRemoteAddr(remoteAddr string) (network string, s string, err error) {
parts := strings.SplitN(remoteAddr, "://", 2)
var protocol, address string
switch {
case len(parts) == 1:
// default to tcp if nothing specified
protocol, address = protoTCP, remoteAddr
case len(parts) == 2:
protocol, address = parts[0], parts[1]
default:
return "", "", fmt.Errorf("invalid addr: %s", remoteAddr)
}
// accept http(s) as an alias for tcp
switch protocol {
case protoHTTP, protoHTTPS:
protocol = protoTCP
}
return protocol, address, nil
}
func makeErrorDialer(err error) func(string, string) (net.Conn, error) {
return func(_ string, _ string) (net.Conn, error) {
return nil, err
@@ -98,13 +91,21 @@ func makeErrorDialer(err error) func(string, string) (net.Conn, error) {
}
func makeHTTPDialer(remoteAddr string) func(string, string) (net.Conn, error) {
protocol, address, err := parseRemoteAddr(remoteAddr)
u, err := newParsedURL(remoteAddr)
if err != nil {
return makeErrorDialer(err)
}
protocol := u.Scheme
// accept http(s) as an alias for tcp
switch protocol {
case protoHTTP, protoHTTPS:
protocol = protoTCP
}
return func(proto, addr string) (net.Conn, error) {
return net.Dial(protocol, address)
return net.Dial(protocol, u.GetHostWithPath())
}
}
@@ -142,10 +143,12 @@ type JSONRPCRequestBatch struct {
// JSONRPCClient takes params as a slice
type JSONRPCClient struct {
address string
client *http.Client
id types.JSONRPCStringID
cdc *amino.Codec
address string
username string
password string
client *http.Client
id types.JSONRPCStringID
cdc *amino.Codec
}
// JSONRPCCaller implementers can facilitate calling the JSON RPC endpoint.
@@ -170,16 +173,24 @@ func NewJSONRPCClientWithHTTPClient(remote string, client *http.Client) *JSONRPC
panic("nil http.Client provided")
}
clientAddress, err := toClientAddress(remote)
parsedURL, err := newParsedURL(remote)
if err != nil {
panic(fmt.Sprintf("invalid remote %s: %s", remote, err))
}
parsedURL.SetDefaultSchemeHTTP()
address := parsedURL.GetTrimmedURL()
username := parsedURL.User.Username()
password, _ := parsedURL.User.Password()
return &JSONRPCClient{
address: clientAddress,
client: client,
id: types.JSONRPCStringID("jsonrpc-client-" + cmn.RandStr(8)),
cdc: amino.NewCodec(),
address: address,
username: username,
password: password,
client: client,
id: types.JSONRPCStringID("jsonrpc-client-" + cmn.RandStr(8)),
cdc: amino.NewCodec(),
}
}
@@ -195,7 +206,15 @@ func (c *JSONRPCClient) Call(method string, params map[string]interface{}, resul
return nil, err
}
requestBuf := bytes.NewBuffer(requestBytes)
httpResponse, err := c.client.Post(c.address, "text/json", requestBuf)
httpRequest, err := http.NewRequest(http.MethodPost, c.address, requestBuf)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Content-Type", "text/json")
if c.username != "" || c.password != "" {
httpRequest.SetBasicAuth(c.username, c.password)
}
httpResponse, err := c.client.Do(httpRequest)
if err != nil {
return nil, err
}
@@ -228,7 +247,15 @@ func (c *JSONRPCClient) sendBatch(requests []*jsonRPCBufferedRequest) ([]interfa
if err != nil {
return nil, err
}
httpResponse, err := c.client.Post(c.address, "text/json", bytes.NewBuffer(requestBytes))
httpRequest, err := http.NewRequest(http.MethodPost, c.address, bytes.NewBuffer(requestBytes))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Content-Type", "text/json")
if c.username != "" || c.password != "" {
httpRequest.SetBasicAuth(c.username, c.password)
}
httpResponse, err := c.client.Do(httpRequest)
if err != nil {
return nil, err
}
@@ -315,12 +342,15 @@ type URIClient struct {
// The function panics if the provided remote is invalid.
func NewURIClient(remote string) *URIClient {
clientAddress, err := toClientAddress(remote)
parsedURL, err := newParsedURL(remote)
if err != nil {
panic(fmt.Sprintf("invalid remote %s: %s", remote, err))
}
parsedURL.SetDefaultSchemeHTTP()
return &URIClient{
address: clientAddress,
address: parsedURL.GetTrimmedURL(),
client: DefaultHTTPClient(remote),
cdc: amino.NewCodec(),
}

View File

@@ -0,0 +1,22 @@
package rpcclient
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestHTTPClientMakeHTTPDialer(t *testing.T) {
remote := []string{"https://foo-bar.com:80", "http://foo-bar.net:80", "https://user:pass@foo-bar.net:80"}
for _, f := range remote {
u, err := newParsedURL(f)
require.NoError(t, err)
dialFn := makeHTTPDialer(f)
addr, err := dialFn(u.Scheme, u.GetHostWithPath())
require.NoError(t, err)
require.NotNil(t, addr)
}
}

View File

@@ -27,7 +27,7 @@ const (
// WSClient is a WebSocket client. The methods of WSClient are safe for use by
// multiple goroutines.
type WSClient struct { // nolint: maligned
type WSClient struct {
conn *websocket.Conn
cdc *amino.Codec
@@ -80,18 +80,18 @@ type WSClient struct { // nolint: maligned
// pong wait time. The endpoint argument must begin with a `/`.
// The function panics if the provided address is invalid.
func NewWSClient(remoteAddr, endpoint string, options ...func(*WSClient)) *WSClient {
protocol, addr, err := toClientAddrAndParse(remoteAddr)
parsedURL, err := newParsedURL(remoteAddr)
if err != nil {
panic(fmt.Sprintf("invalid remote %s: %s", remoteAddr, err))
}
// default to ws protocol, unless wss is explicitly specified
if protocol != "wss" {
protocol = "ws"
if parsedURL.Scheme != protoWSS {
parsedURL.Scheme = protoWS
}
c := &WSClient{
cdc: amino.NewCodec(),
Address: addr,
Address: parsedURL.GetTrimmedHostWithPath(),
Dialer: makeHTTPDialer(remoteAddr),
Endpoint: endpoint,
PingPongLatencyTimer: metrics.NewTimer(),
@@ -100,7 +100,7 @@ func NewWSClient(remoteAddr, endpoint string, options ...func(*WSClient)) *WSCli
readWait: defaultReadWait,
writeWait: defaultWriteWait,
pingPeriod: defaultPingPeriod,
protocol: protocol,
protocol: parsedURL.Scheme,
}
c.BaseService = *cmn.NewBaseService(nil, "WSClient", c)
for _, option := range options {

View File

@@ -64,7 +64,8 @@ func TestWSClientReconnectsAfterReadFailure(t *testing.T) {
s := httptest.NewServer(h)
defer s.Close()
c := startClient(t, s.Listener.Addr().String())
// https://github.com/golang/go/issues/19297#issuecomment-282651469
c := startClient(t, "//"+s.Listener.Addr().String())
defer c.Stop()
wg.Add(1)
@@ -96,7 +97,8 @@ func TestWSClientReconnectsAfterWriteFailure(t *testing.T) {
h := &myHandler{}
s := httptest.NewServer(h)
c := startClient(t, s.Listener.Addr().String())
// https://github.com/golang/go/issues/19297#issuecomment-282651469
c := startClient(t, "//"+s.Listener.Addr().String())
defer c.Stop()
wg.Add(2)
@@ -124,7 +126,8 @@ func TestWSClientReconnectFailure(t *testing.T) {
h := &myHandler{}
s := httptest.NewServer(h)
c := startClient(t, s.Listener.Addr().String())
// https://github.com/golang/go/issues/19297#issuecomment-282651469
c := startClient(t, "//"+s.Listener.Addr().String())
defer c.Stop()
go func() {
@@ -173,7 +176,7 @@ func TestWSClientReconnectFailure(t *testing.T) {
func TestNotBlockingOnStop(t *testing.T) {
timeout := 2 * time.Second
s := httptest.NewServer(&myHandler{})
c := startClient(t, s.Listener.Addr().String())
c := startClient(t, "//"+s.Listener.Addr().String())
c.Call(context.Background(), "a", make(map[string]interface{}))
// Let the readRoutine get around to blocking
time.Sleep(time.Second)

View File

@@ -36,11 +36,11 @@ function getCode() {
# build grpc client if needed
if [[ "$GRPC_BROADCAST_TX" != "" ]]; then
if [ -f grpc_client ]; then
rm grpc_client
if [ -f test/app/grpc_client ]; then
rm test/app/grpc_client
fi
echo "... building grpc_client"
go build -mod=readonly -o grpc_client grpc_client.go
go build -mod=readonly -o test/app/grpc_client test/app/grpc_client.go
fi
function sendTx() {
@@ -59,7 +59,7 @@ function sendTx() {
RESPONSE=$(echo "$RESPONSE" | jq '.result')
else
RESPONSE=$(./grpc_client "$TX")
RESPONSE=$(./test/app/grpc_client "$TX")
IS_ERR=false
ERROR=""
fi

View File

@@ -22,7 +22,7 @@ function kvstore_over_socket(){
sleep 5
echo "running test"
bash kvstore_test.sh "KVStore over Socket"
bash test/app/kvstore_test.sh "KVStore over Socket"
kill -9 $pid_kvstore $pid_tendermint
}
@@ -40,7 +40,7 @@ function kvstore_over_socket_reorder(){
sleep 5
echo "running test"
bash kvstore_test.sh "KVStore over Socket"
bash test/app/kvstore_test.sh "KVStore over Socket"
kill -9 $pid_kvstore $pid_tendermint
}
@@ -57,7 +57,7 @@ function counter_over_socket() {
sleep 5
echo "running test"
bash counter_test.sh "Counter over Socket"
bash test/app/counter_test.sh "Counter over Socket"
kill -9 $pid_counter $pid_tendermint
}
@@ -73,7 +73,7 @@ function counter_over_grpc() {
sleep 5
echo "running test"
bash counter_test.sh "Counter over GRPC"
bash test/app/counter_test.sh "Counter over GRPC"
kill -9 $pid_counter $pid_tendermint
}
@@ -91,13 +91,11 @@ function counter_over_grpc_grpc() {
sleep 5
echo "running test"
GRPC_BROADCAST_TX=true bash counter_test.sh "Counter over GRPC via GRPC BroadcastTx"
GRPC_BROADCAST_TX=true bash test/app/counter_test.sh "Counter over GRPC via GRPC BroadcastTx"
kill -9 $pid_counter $pid_tendermint
}
cd $GOPATH/src/github.com/tendermint/tendermint/test/app
case "$1" in
"kvstore_over_socket")
kvstore_over_socket
@@ -126,4 +124,3 @@ case "$1" in
echo ""
counter_over_grpc_grpc
esac

View File

@@ -1,8 +1,5 @@
FROM golang:1.13
# Add testing deps for curl
RUN echo 'deb http://httpredir.debian.org/debian testing main non-free contrib' >> /etc/apt/sources.list
# Grab deps (jq, hexdump, xxd, killall)
RUN apt-get update && \
apt-get install -y --no-install-recommends \
@@ -28,11 +25,11 @@ RUN make install_abci
RUN make install
RUN tendermint testnet \
--config $REPO/test/docker/config-template.toml \
--node-dir-prefix="mach" \
--v=4 \
--populate-persistent-peers=false \
--o=$REPO/test/p2p/data
--config $REPO/test/docker/config-template.toml \
--node-dir-prefix="mach" \
--v=4 \
--populate-persistent-peers=false \
--o=$REPO/test/p2p/data
# Now copy in the code
# NOTE: this will overwrite whatever is in vendor/

View File

@@ -20,7 +20,8 @@ const (
// Must be a string because scripts like dist.sh read this file.
// XXX: Don't change the name of this variable or you will break
// automation :)
TMCoreSemVer = "0.32.7"
TMCoreSemVer = "0.32.14"
// ABCISemVer is the semantic version of the ABCI library
ABCISemVer = "0.16.1"
@@ -33,6 +34,7 @@ type Protocol uint64
// Uint64 returns the Protocol version as a uint64,
// eg. for compatibility with ABCI types.
func (p Protocol) Uint64() uint64 {
return uint64(p)
}