Compare commits

...

1915 Commits

Author SHA1 Message Date
4accdb5f59 Example of client send task and monitor task 2018-04-19 12:34:42 +02:00
ece3f678da [docs/spec] update msg type and Tendermint behavior (#1468)
Refs #1422
2018-04-17 19:38:10 +02:00
45a05b4726 Merge pull request #1461 from tendermint/update-changelog
update changelog
2018-04-17 09:56:53 +02:00
1706ce6f7f update changelog for 0.19.0 release 2018-04-13 10:50:34 +02:00
d0beaba7e8 Bump version to 0.19.0 2018-04-13 01:32:47 -07:00
c28784de5e Merge pull request #1453 from tendermint/fix-localnet
Fix permissions and folder structure for localnet
2018-04-12 17:50:08 +02:00
d06390638d [localnet] use routable IPs 2018-04-12 16:02:31 +02:00
3a0edc561d log error from AddrBook#AddAddress in DialPeersAsync
Refs #1434
2018-04-12 15:51:17 +02:00
f8ed578325 [localnet] execute cmd from root
not secure, but we don't care because it's local tooling
2018-04-12 15:51:32 +02:00
5babaf9a88 [localnet] fix folder permissions errors 2018-04-12 15:51:17 +02:00
c0610b2c32 Greg/localnet (#1450)
* Added new Makefile targets for local testnet running using docker

* Added localnode docker image description, some documentation and refactored to use the tendermint testnet command

* Fixes for the new tendermint testnet command

* More fixes on tendermint testnet and docker-compose

* Changed logging

* Added missing targets to phony
2018-04-12 13:15:16 +02:00
1db2224241 do not use mask in testnet cmd (#1451)
fix node ids
2018-04-11 20:53:33 +02:00
0323b03daf improve testnet cmd (#1449)
* improve testnet cmd

* allow non-validators
* configurable prefix
* populating of persistent peers

* relax permissions

* cleanup output dir every time

* do not remove dir

* remove panic comments
2018-04-11 19:40:53 +02:00
379f9f875b update docs for latest develop (#1448)
* update docs for latest develop

* latest_app_hash, not app_hash
2018-04-11 17:36:14 +02:00
ab00bf7c8b standardize PRNG access (#1411)
* replace math/rand with tmlibs equivalent.

* update tmlibs dependency
2018-04-11 11:38:30 +02:00
64879c1e6a 1417 status response format (#1424)
* Reformated the ResultStatus

* fix misuse of ResultStatus.

* updated changelog

* Fixed tests

* fixed rpc helper tests

* fixed rpc_tests

* fixed mock/status_test

* fixed typo

* fixed ommitempty on validatorstatus and the changelog

* fixed extra line in changelog

* Updated usage of the /status json response in tests after breaking changes

* Updated remaining tests with changes after searching the codebase for usage

* Reformated the ResultStatus

* fix misuse of ResultStatus.

* updated changelog

* Fixed tests

* fixed rpc helper tests

* fixed rpc_tests

* fixed mock/status_test

* fixed typo

* fixed ommitempty on validatorstatus and the changelog

* Updated usage of the /status json response in tests after breaking changes

* Updated remaining tests with changes after searching the codebase for usage

* rebased against develop
2018-04-11 10:38:34 +02:00
7c22e47629 Replaced NodeInfo's pubkey to ID (#1443)
* Replaced NodeInfo PubKey to NodeID

* Fixed tests and replaced NodeID with ID

* Removed unnecessary method ID()

* Fixed codec_test.go

* Fixed codec_test.go

* Removed unnecessary bracket

* Fixed all tests

* Fixed peer_set_test.go

* Fixed peer_test.go

* Fixed common_test.go

* Fixed common_test.go

* Renamed node_id to id

* Removed peer.ID() from RPC net.go

* Replaced NodeInfo pubKey to ID

* Fixed codec_test.go

* Fixed peer_set_test.go

* Fix pex_reactor_test.go

* Refactored code for privateKey initiali

* Fixed peer_set_test.go

* Fixed test.proto and removed orphan string in codec_test.go

* Fixed pointer to a string

* generate node_key when running tendermint init

* [docs] prefix IPs with node IDs

Refs #1429

* gen_node_key cmd

* [docs/specification/secure-p2p] add a note about config

* fix data race

Closes #1442

```
WARNING: DATA RACE
Write at 0x00c4209de7c8 by goroutine 23:
  github.com/tendermint/tendermint/types.(*Block).fillHeader()
      /home/vagrant/go/src/github.com/tendermint/tendermint/types/block.go:88 +0x157
  github.com/tendermint/tendermint/types.(*Block).Hash()
      /home/vagrant/go/src/github.com/tendermint/tendermint/types/block.go:104 +0x121
  github.com/tendermint/tendermint/types.(*Block).HashesTo()
      /home/vagrant/go/src/github.com/tendermint/tendermint/types/block.go:135 +0x4f
  github.com/tendermint/tendermint/consensus.(*ConsensusState).enterPrecommit()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1037 +0x182d
  github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1425 +0x1a6c
  github.com/tendermint/tendermint/consensus.(*ConsensusState).tryAddVote()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1318 +0x77
  github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:581 +0x7a9
  github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:539 +0x6c3

Previous read at 0x00c4209de7c8 by goroutine 47:
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*HexBytes).MarshalJSON()
      <autogenerated>:1 +0x52
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.invokeMarshalJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:433 +0x88
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:82 +0x8d2
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSONStruct()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:348 +0x539
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:119 +0x83f
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSONStruct()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:348 +0x539
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:119 +0x83f
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSONStruct()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:348 +0x539
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:119 +0x83f
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSONStruct()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:348 +0x539
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:119 +0x83f
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).MarshalJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/amino.go:296 +0x182
  github.com/tendermint/tendermint/rpc/lib/types.NewRPCSuccessResponse()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/lib/types/types.go:100 +0x12c
  github.com/tendermint/tendermint/rpc/lib/server.makeJSONRPCHandler.func1()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/lib/server/handlers.go:152 +0xab7
  net/http.HandlerFunc.ServeHTTP()
      /usr/lib/go-1.9/src/net/http/server.go:1918 +0x51
  net/http.(*ServeMux).ServeHTTP()
      /usr/lib/go-1.9/src/net/http/server.go:2254 +0xa2
  github.com/tendermint/tendermint/rpc/lib/server.RecoverAndLogHandler.func1()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/lib/server/http_server.go:138 +0x4fa
  net/http.HandlerFunc.ServeHTTP()
      /usr/lib/go-1.9/src/net/http/server.go:1918 +0x51
  net/http.serverHandler.ServeHTTP()
      /usr/lib/go-1.9/src/net/http/server.go:2619 +0xbc
  net/http.(*conn).serve()
      /usr/lib/go-1.9/src/net/http/server.go:1801 +0x83b

Goroutine 23 (running) created at:
  github.com/tendermint/tendermint/consensus.(*ConsensusState).OnStart()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:250 +0x35b
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x5fc
  github.com/tendermint/tendermint/consensus.(*ConsensusReactor).OnStart()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/reactor.go:69 +0x1b4
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x5fc
  github.com/tendermint/tendermint/consensus.(*ConsensusReactor).Start()
      <autogenerated>:1 +0x43
  github.com/tendermint/tendermint/p2p.(*Switch).OnStart()
      /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch.go:177 +0x124
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x5fc
  github.com/tendermint/tendermint/node.(*Node).OnStart()
      /home/vagrant/go/src/github.com/tendermint/tendermint/node/node.go:416 +0xa1b
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x5fc
  github.com/tendermint/tendermint/rpc/test.StartTendermint()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/test/helpers.go:100 +0x5b
  github.com/tendermint/tendermint/rpc/client_test.TestMain()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/client/main_test.go:17 +0x4c
  main.main()
      github.com/tendermint/tendermint/rpc/client/_test/_testmain.go:76 +0x1cd

Goroutine 47 (running) created at:
  net/http.(*Server).Serve()
      /usr/lib/go-1.9/src/net/http/server.go:2720 +0x37c
  net/http.Serve()
      /usr/lib/go-1.9/src/net/http/server.go:2323 +0xe2
  github.com/tendermint/tendermint/rpc/lib/server.StartHTTPServer.func1()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/lib/server/http_server.go:35 +0xb3
```

* removed excessive comment

Refs https://github.com/tendermint/tendermint/pull/1446#discussion_r180353446

* use the tag interface for pubsub. (#1438)

* use the tag interface for pubsub.

* update tmlibs.

* Fix unresolved conflict.

* improve `show_node_id` (#1433)

* fix show_node_id

* make LoadNodeKey public

* make LoadNodeKey public

* remove if

* remove if
2018-04-11 10:11:11 +02:00
384b3ea065 improve show_node_id (#1433)
* fix show_node_id

* make LoadNodeKey public

* make LoadNodeKey public

* remove if

* remove if
2018-04-10 16:03:51 +02:00
6a48bd0c88 use the tag interface for pubsub. (#1438)
* use the tag interface for pubsub.

* update tmlibs.

* Fix unresolved conflict.
2018-04-10 16:03:03 +02:00
d93e177a69 Merge pull request #1446 from tendermint/1442-data-race-fix-attempt
fix data race
2018-04-10 16:49:36 +03:00
cef053386b Merge pull request #1439 from tendermint/1429-add-docs-for-node-ids
docs: update docs to include IDs or set auth_enc to false
2018-04-10 11:46:48 +02:00
cca1dd8e3e removed excessive comment
Refs https://github.com/tendermint/tendermint/pull/1446#discussion_r180353446
2018-04-10 11:36:31 +02:00
26c38e770e fix data race
Closes #1442

```
WARNING: DATA RACE
Write at 0x00c4209de7c8 by goroutine 23:
  github.com/tendermint/tendermint/types.(*Block).fillHeader()
      /home/vagrant/go/src/github.com/tendermint/tendermint/types/block.go:88 +0x157
  github.com/tendermint/tendermint/types.(*Block).Hash()
      /home/vagrant/go/src/github.com/tendermint/tendermint/types/block.go:104 +0x121
  github.com/tendermint/tendermint/types.(*Block).HashesTo()
      /home/vagrant/go/src/github.com/tendermint/tendermint/types/block.go:135 +0x4f
  github.com/tendermint/tendermint/consensus.(*ConsensusState).enterPrecommit()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1037 +0x182d
  github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1425 +0x1a6c
  github.com/tendermint/tendermint/consensus.(*ConsensusState).tryAddVote()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1318 +0x77
  github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:581 +0x7a9
  github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:539 +0x6c3

Previous read at 0x00c4209de7c8 by goroutine 47:
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*HexBytes).MarshalJSON()
      <autogenerated>:1 +0x52
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.invokeMarshalJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:433 +0x88
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:82 +0x8d2
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSONStruct()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:348 +0x539
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:119 +0x83f
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSONStruct()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:348 +0x539
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:119 +0x83f
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSONStruct()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:348 +0x539
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:119 +0x83f
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSONStruct()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:348 +0x539
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec)._encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:119 +0x83f
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).encodeReflectJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/json-encode.go:50 +0x10e
  github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino.(*Codec).MarshalJSON()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-amino/amino.go:296 +0x182
  github.com/tendermint/tendermint/rpc/lib/types.NewRPCSuccessResponse()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/lib/types/types.go:100 +0x12c
  github.com/tendermint/tendermint/rpc/lib/server.makeJSONRPCHandler.func1()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/lib/server/handlers.go:152 +0xab7
  net/http.HandlerFunc.ServeHTTP()
      /usr/lib/go-1.9/src/net/http/server.go:1918 +0x51
  net/http.(*ServeMux).ServeHTTP()
      /usr/lib/go-1.9/src/net/http/server.go:2254 +0xa2
  github.com/tendermint/tendermint/rpc/lib/server.RecoverAndLogHandler.func1()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/lib/server/http_server.go:138 +0x4fa
  net/http.HandlerFunc.ServeHTTP()
      /usr/lib/go-1.9/src/net/http/server.go:1918 +0x51
  net/http.serverHandler.ServeHTTP()
      /usr/lib/go-1.9/src/net/http/server.go:2619 +0xbc
  net/http.(*conn).serve()
      /usr/lib/go-1.9/src/net/http/server.go:1801 +0x83b

Goroutine 23 (running) created at:
  github.com/tendermint/tendermint/consensus.(*ConsensusState).OnStart()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:250 +0x35b
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x5fc
  github.com/tendermint/tendermint/consensus.(*ConsensusReactor).OnStart()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/reactor.go:69 +0x1b4
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x5fc
  github.com/tendermint/tendermint/consensus.(*ConsensusReactor).Start()
      <autogenerated>:1 +0x43
  github.com/tendermint/tendermint/p2p.(*Switch).OnStart()
      /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch.go:177 +0x124
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x5fc
  github.com/tendermint/tendermint/node.(*Node).OnStart()
      /home/vagrant/go/src/github.com/tendermint/tendermint/node/node.go:416 +0xa1b
  github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start()
      /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x5fc
  github.com/tendermint/tendermint/rpc/test.StartTendermint()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/test/helpers.go:100 +0x5b
  github.com/tendermint/tendermint/rpc/client_test.TestMain()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/client/main_test.go:17 +0x4c
  main.main()
      github.com/tendermint/tendermint/rpc/client/_test/_testmain.go:76 +0x1cd

Goroutine 47 (running) created at:
  net/http.(*Server).Serve()
      /usr/lib/go-1.9/src/net/http/server.go:2720 +0x37c
  net/http.Serve()
      /usr/lib/go-1.9/src/net/http/server.go:2323 +0xe2
  github.com/tendermint/tendermint/rpc/lib/server.StartHTTPServer.func1()
      /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/lib/server/http_server.go:35 +0xb3
```
2018-04-10 11:15:16 +02:00
609452958c [docs/specification/secure-p2p] add a note about config 2018-04-09 17:02:48 +02:00
c954fca376 gen_node_key cmd 2018-04-09 17:02:47 +02:00
9be16d56ba [docs] prefix IPs with node IDs
Refs #1429
2018-04-09 17:02:47 +02:00
2b732bc11a generate node_key when running tendermint init 2018-04-09 17:02:47 +02:00
dcd00b0e68 update deps and changelog 2018-04-09 16:36:42 +03:00
ff3f35c5f4 Merge pull request #1347 from tendermint/jae/aminoify
Convert Tendermint to use GoAmino
2018-04-09 16:24:38 +03:00
93c4312cdd Merge pull request #1432 from tendermint/bucky/aminoify
Bucky/aminoify
2018-04-09 15:20:36 +03:00
1a1e4e767b check max msg size in DecodeMessage 2018-04-09 15:18:47 +03:00
bb1b249e8a types: lock block on MakePartSet 2018-04-09 15:04:59 +03:00
c778d7f5d1 fix addresses 2018-04-07 23:13:41 +03:00
bb9b12d67a add scripts/wire2amino.go 2018-04-07 22:04:28 +03:00
767521ac52 update test/p2p/data for amino 2018-04-07 22:03:48 +03:00
df9bf60b05 forgot Gopkg.lock 2018-04-07 20:59:13 +03:00
466c3ab1c7 forgot node/wire.go 2018-04-07 19:53:29 +03:00
c68d406195 fix tests 2018-04-07 19:47:19 +03:00
02c0835e9b fixes post merge 2018-04-07 16:25:10 +03:00
c170800fbd Merge branch 'develop' into jae/aminoify 2018-04-07 16:16:53 +03:00
7afe74a963 Update go-crypto to 0.6.1 and change config/toml.go privval address 2018-04-07 02:01:45 -07:00
02531ca5a3 Fix race testing (cont;) Bump version to 0.19.0 2018-04-06 17:06:46 -07:00
d24e4cb821 Fix race testing 2018-04-06 17:02:29 -07:00
fb64314d1c Review from Anton 2018-04-06 13:46:40 -07:00
4930b61a38 Merge pull request #1431 from tendermint/release/v0.18.0
Release/v0.18.0
2018-04-06 23:19:09 +03:00
9cc2cf362f changelog and version 2018-04-06 23:03:27 +03:00
ed93fb34ab Merge pull request #1350 from tendermint/1275-p2p-loopbacks
p2p: loopbacks should be detected and ignored instead of dialling self infinitely
2018-04-06 18:59:05 +03:00
3d32474da8 make linter happy 2018-04-06 13:26:05 +02:00
3233c318ea only log errors, dial correct addresses
"this means if there are lookup errors or typos in the persistent_peers,
tendermint will fail to start ? didn't some one ask for us not to do
this previously ?"
2018-04-06 12:35:48 +02:00
32e1d195a0 Fix cmd and lite 2018-04-05 22:05:30 -07:00
3ca5292dc9 Fix rpc tests 2018-04-05 21:19:14 -07:00
c541d58d2f WIP: fix rpc/core 2018-04-05 16:07:29 -07:00
3037b5b7ca Fix rpc/lib/... 2018-04-05 15:45:11 -07:00
c9a263c589 Merge pull request #1389 from tendermint/1380-trim-whitespaces
trim whitespace from elements of lists (like `persistent_peers`)
2018-04-05 18:22:46 +03:00
e4492afbad Merge 2018-04-05 08:17:10 -07:00
799beebd36 fix consensus tests 2018-04-05 17:54:26 +03:00
45ec5fd170 WIP consensus 2018-04-05 07:05:45 -07:00
6e39ec6e26 do not even try to dial ourselves
also, remove address from the book (plus mark it as our address)
and return an error if we fail to parse peers list
2018-04-05 15:45:52 +02:00
d38a6cc7ea trim whitespace from elements of lists (like persistent_peers)
Refs #1380
2018-04-05 16:42:26 +03:00
7f6ee7a46b add a comment for NewSwitch 2018-04-05 15:27:47 +02:00
34b77fcad4 log error when we fail to add new address 2018-04-05 15:27:47 +02:00
3b3f45d49b use addrbook#AddOurAddress to store our address 2018-04-05 15:27:47 +02:00
3284a13fee add test
Refs #1275
2018-04-05 15:27:47 +02:00
fc9ffee2e3 remove unused tracking because it leads to memory leaks in tests
see https://blog.cosmos.network/debugging-the-memory-leak-in-tendermint-210186711420
2018-04-05 15:27:47 +02:00
3a672cb2a9 update changelog [ci skip] 2018-04-05 15:27:46 +02:00
4b8e342309 fix panic: lookup testing on 10.0.2.3:53: no such host 2018-04-05 15:27:46 +02:00
5a2fa71b03 use combination of IP and port, not just IP 2018-04-05 15:27:46 +02:00
9a57ef9cbf do not dial ourselves (ok, maybe just once)
Refs #1275
2018-04-05 15:27:46 +02:00
59ca9bf480 update to tmlibs v0.8.1 2018-04-05 16:16:36 +03:00
7cce07bc99 Merge pull request #1352 from tendermint/1228-require-id
p2p: require all addresses come with an ID no matter what
2018-04-05 15:55:41 +03:00
0ae66f75ce Merge pull request #1420 from tendermint/1414-data-race
protect Record* peerStateStats functions by mutex
2018-04-05 15:53:15 +03:00
5d1c758730 Fix evidence 2018-04-05 05:43:23 -07:00
1b9323f105 Fix blockchain tests 2018-04-05 05:17:43 -07:00
cee7b5cb54 GetSelectionWithBias
Refs #1130
2018-04-05 12:00:16 +02:00
1585152341 https://github.com/tendermint/tendermint/pull/1128#discussion_r162799294
Refs #1130
2018-04-05 12:00:16 +02:00
8e699c2bfd defaultSeedDisconnectWaitPeriod should be at least as long as we expect
it to take for a peer to become MarkGood

Refs #1130
2018-04-05 12:00:16 +02:00
904a3115a6 require addresses to have an ID by default
Refs #1228
2018-04-05 11:55:29 +02:00
a506cf47ad protect Record* peerStateStats functions by mutex
Fixes #1414

DATA RACE:
```
Read at 0x00c4214ee940 by goroutine 146:
  github.com/tendermint/tendermint/consensus.(*peerStateStats).String()
      <autogenerated>:1 +0x57
  fmt.(*pp).handleMethods()
      /usr/local/go/src/fmt/print.go:596 +0x3f4
  fmt.(*pp).printArg()
      /usr/local/go/src/fmt/print.go:679 +0x11f
  fmt.(*pp).doPrintf()
      /usr/local/go/src/fmt/print.go:996 +0x319
  fmt.Sprintf()
      /usr/local/go/src/fmt/print.go:196 +0x73
  github.com/tendermint/tendermint/consensus.(*PeerState).StringIndented()
      github.com/tendermint/tendermint/consensus/_test/_obj_test/reactor.go:1426 +0x573
  github.com/tendermint/tendermint/consensus.(*PeerState).String()
      github.com/tendermint/tendermint/consensus/_test/_obj_test/reactor.go:1419 +0x66
  github.com/go-logfmt/logfmt.safeString()
      /home/ubuntu/go/src/github.com/go-logfmt/logfmt/encode.go:299 +0x9d
  github.com/go-logfmt/logfmt.writeValue()
      /home/ubuntu/go/src/github.com/go-logfmt/logfmt/encode.go:217 +0x5a0
  github.com/go-logfmt/logfmt.(*Encoder).EncodeKeyval()
      /home/ubuntu/go/src/github.com/go-logfmt/logfmt/encode.go:61 +0x1dd
  github.com/tendermint/tmlibs/log.tmfmtLogger.Log()
      /home/ubuntu/go/src/github.com/tendermint/tmlibs/log/tmfmt_logger.go:107 +0x1001
  github.com/tendermint/tmlibs/log.(*tmfmtLogger).Log()
      <autogenerated>:1 +0x93
  github.com/go-kit/kit/log.(*context).Log()
      /home/ubuntu/go/src/github.com/go-kit/kit/log/log.go:124 +0x248
  github.com/tendermint/tmlibs/log.(*tmLogger).Debug()
      /home/ubuntu/go/src/github.com/tendermint/tmlibs/log/tm_logger.go:64 +0x1d0
  github.com/tendermint/tendermint/consensus.(*PeerState).PickSendVote()
      github.com/tendermint/tendermint/consensus/_test/_obj_test/reactor.go:1059 +0x242
  github.com/tendermint/tendermint/consensus.(*ConsensusReactor).gossipVotesForHeight()
      github.com/tendermint/tendermint/consensus/_test/_obj_test/reactor.go:789 +0x6ef
  github.com/tendermint/tendermint/consensus.(*ConsensusReactor).gossipVotesRoutine()
      github.com/tendermint/tendermint/consensus/_test/_obj_test/reactor.go:723 +0x1039

Previous write at 0x00c4214ee940 by goroutine 21:
  github.com/tendermint/tendermint/consensus.(*PeerState).RecordVote()
      github.com/tendermint/tendermint/consensus/_test/_obj_test/reactor.go:1242 +0x15a
  github.com/tendermint/tendermint/consensus.(*ConsensusReactor).Receive()
      github.com/tendermint/tendermint/consensus/_test/_obj_test/reactor.go:309 +0x32e6
  github.com/tendermint/tendermint/p2p.createMConnection.func1()
      /home/ubuntu/go/src/github.com/tendermint/tendermint/p2p/peer.go:365 +0xea
  github.com/tendermint/tendermint/p2p/conn.(*MConnection).recvRoutine()
      /home/ubuntu/go/src/github.com/tendermint/tendermint/p2p/conn/connection.go:531 +0x779
```
2018-04-05 11:42:45 +02:00
7689c15413 Merge pull request #1378 from tendermint/bucky/disable-test-libs
comment out test_libs because of gcc dep in tmlibs
2018-04-05 11:06:30 +02:00
f907113c19 Net_info should print the ID of peers (#1312) 2018-04-05 11:02:23 +02:00
140f962201 Merge pull request #1406 from tendermint/docker
Update dockerfile and readme
2018-04-05 10:57:19 +02:00
c23d907f12 Merge pull request #1391 from tendermint/581-include-validator-power
Include validator power in /status
2018-04-05 11:18:45 +03:00
ed782e7508 include validator's voting power in /status
Refs #581
2018-04-04 11:34:59 +02:00
0732526465 use more relaxing < and >= ops instead of !=
an example of Search from godocs:

```
package main

import (
	"fmt"
	"sort"
)

func main() {
	a := []int{1, 3, 6, 10, 15, 21, 28, 36, 45, 55}
	x := 6

	i := sort.Search(len(a), func(i int) bool { return a[i] >= x })
	if i < len(a) && a[i] == x {
		fmt.Printf("found %d at index %d in %v\n", x, i, a)
	} else {
		fmt.Printf("%d not found in %v\n", x, a)
	}
}
```
2018-04-04 10:42:35 +02:00
39a4963782 document funcs in validator_set.go 2018-04-04 10:42:35 +02:00
37ce6b195a ValidatorSet#GetByAddress: return -1 if no validator was found 2018-04-04 10:42:34 +02:00
7aa6d36258 Merge pull request #1412 from tendermint/bucky/exit-conR-subscribe-routine
consensus: check for closed subscription channels and exit routine
2018-04-03 23:53:48 +03:00
991017fc41 Merge pull request #1336 from tendermint/zarko/1308-add-light-client-spec
Add light client spec
2018-04-03 23:02:32 +03:00
5f548c7679 consensus: close pubsub channels. fixes #1372 2018-04-03 22:57:32 +03:00
d14aacf03e Merge pull request #1300 from tendermint/lite-proxy-hardening-and-tests
lite/proxy: Validation* tests and hardening for nil dereferences
2018-04-03 22:43:38 +03:00
39ff4d22e9 minor cleanup 2018-04-03 22:34:18 +03:00
196f8410ba WIP commit; Fix types/results_test 2018-04-03 07:03:08 -07:00
8462493cbf [rpc] fix subscribing using an abci.ResponseDeliverTx tag
Refs #1369
2018-04-03 15:53:13 +02:00
47b8bd1728 wrote a test for EventBus#PublishEventTx
Refs #1369
2018-04-03 15:53:13 +02:00
89cdde7f1e Fix state tests 2018-04-03 06:50:53 -07:00
657fd671ea Merge pull request #1409 from tendermint/zach/docs/tm-monitor
docs: build updates
2018-04-03 15:24:55 +03:00
315c475b79 docs: build updates
ref: https://github.com/tendermint/tools/pull/79
2018-04-03 04:48:40 -07:00
b800b4ec1d update docker readme 2018-04-02 16:57:25 +02:00
208ac32fa2 update Dockerfile to point to 0.17.1 release 2018-04-02 16:56:07 +02:00
641476d40f update docker to use alpine 3.7 2018-04-02 16:55:43 +02:00
491c8ab4c1 [rpc/lib] log cert and key files in StartHTTPAndTLSServer 2018-04-02 15:21:05 +02:00
5ef8a6e887 deprecate not fully formed addresses 2018-04-02 15:21:05 +02:00
d694d47d22 [rpc/lib] rename vars according to Go conventions 2018-04-02 15:21:05 +02:00
ecdc1b9bb0 Add a method for creating an https server (#1403) 2018-04-02 11:36:09 +02:00
9c757108ca [test] remove test_libs
Reasons:
1) all deps we're using should be passing tests (including external)
2) deps can require complicated setup for testing
3) the person responsible for releasing Tendermint should be cautious
when updating a dep
2018-04-02 11:29:03 +02:00
5243e54641 [codecov] ignore docs, scripts and DOCKER dirs 2018-04-02 11:23:56 +02:00
70e7454c21 comment out test_libs because of gcc dep in tmlibs 2018-04-02 11:23:56 +02:00
2644a529f0 Fix lint errors (#1390)
* use increment and decrement operators.

* remove unnecessary else branches.

* fix package comment with leading space.

* fix receiver names.

* fix error strings.

* remove omittable code.

* remove redundant return statement.

* Revert changes (code is generated.)

* use cfg as receiver name for all config-related types.

* use lsi as the receiver name for the LastSignedInfo type.
2018-04-02 10:21:17 +02:00
eaee98ee1f CGO_ENABLED=0 added for static linking (#1396) 2018-04-01 19:54:48 +02:00
35a1d747b0 Fix mempool 2018-03-31 11:51:32 +02:00
34974e3932 Make types use Amino; Refactor PrivValidator* to FilePV/SocketPV 2018-03-31 00:18:43 +02:00
575a46d9d4 fix typo on block header (#1387) 2018-03-29 11:28:29 +02:00
bcadbd1b10 Merge pull request #1376 from tendermint/1368-unsubscribe-does-not-work
[rpc] unsubscribe does not work
2018-03-28 15:13:40 -04:00
ead9daf1ba Fix code style (#1362)
* cfg: Uniform style for method args and var names
2018-03-28 13:40:47 -04:00
22949e6dfd new tmlibs Parallel implementation 2018-03-28 19:13:08 +02:00
49986b05bc update tmlibs
Refs #1376
2018-03-28 19:12:52 +02:00
2fa7af4614 [lite] fixed listen address (#1384) 2018-03-28 15:59:09 +02:00
2d857c4b1b add hash field to ResultTx (/tx and /tx_search endpoints) (#1374)
Refs #1367
2018-03-28 15:44:58 +02:00
2b63f57b4c fix tx_indexer's matchRange
before we're using IteratePrefix, which is wrong because we want full
range, not just "account.number=1".
2018-03-28 15:02:54 +02:00
4085c72496 sort /tx_search results by height by default
Refs #1366
2018-03-28 15:02:54 +02:00
6f9956990c Merge pull request #1377 from tendermint/release/0.17.1
Release/0.17.1
2018-03-27 11:24:48 -04:00
9bf5862def types: fix genesis.AppStateJSON 2018-03-27 11:20:09 -04:00
e1d98bb7f6 forgot bug fix in changelog 2018-03-27 10:06:30 -04:00
e5cd006bce Merge pull request #1373 from tendermint/release/0.17.0
Release/0.17.0
2018-03-27 09:57:10 -04:00
58242e1b63 bump version one more time 2018-03-27 09:07:29 +02:00
4e86835163 update changelog for 0.17.0 release 2018-03-27 09:06:32 +02:00
ab4ac04c88 bump up the version 2018-03-26 22:07:07 +02:00
2c1887a635 update changelog 2018-03-26 22:06:58 +02:00
1c82281b77 make app_options -> app_state backwards compatible 2018-03-26 21:51:07 +02:00
43ac92b615 Changed to make line break easier to read (#1363) 2018-03-26 16:27:20 +02:00
901b456151 P2P now works with Amino 2018-03-26 06:40:02 +02:00
8813684040 lite/proxy: consolidate some common test headers into a variable
Addressing some feedback from @ebuchman in regards to
consolidating some common test headers into a variable.

I've added that for simple cases, trying to meet in the middle
instead of creating helpers that obscure readibility and easy
comparison of test cases.
2018-03-25 00:27:42 -06:00
58f36bb321 Review feedback from @melekes
* Fix typo on naming s/deabBeef/deadBeef/g
* Use `assert.*(t,` instead of `assert.New(t);...;assert.*(`
2018-03-24 23:54:01 -06:00
4c2f56626a lite/proxy: Validation* tests and hardening for nil dereferences
Updates https://github.com/tendermint/tendermint/issues/1017

Ensure that the Validate* functions in proxy are tests
and cover the case of sneakish bugs that have been encountered
a few times from nil dereferences. The lite package should
theoretically never panic with a nil dereference. It is meant
to contain the certifiers hence it should never panic with such.

Requires the following bugs to be fixed first;
* https://github.com/tendermint/tendermint/issues/1298
* https://github.com/tendermint/tendermint/issues/1299
2018-03-24 23:54:01 -06:00
e3337d764a Merge pull request #1354 from tendermint/bucky/dep
update dep
2018-03-24 12:14:56 -04:00
214817ed17 do not add peer to switch if it fails to start 2018-03-23 13:31:48 +01:00
116a4ec705 temporary fix
I assume there is a deeper issue with how UnmarshalBinary works in
go-amino (i.e., when loading array of some objects, the empty array
becomes []object{nil}). Note when Marshaling, the object is nil.
2018-03-23 12:47:02 +01:00
bbaad22982 update dep 2018-03-23 10:27:00 +01:00
a7250af303 Exponential backoff follow up (#1349)
* document new functionality [ci skip]

Refs #1304

* add fixme [ci skip]

Refs #1304

* ensure that we dial peer after backoff duration

Refs #1304
2018-03-23 09:48:27 +01:00
6545a21369 docs/examples: update quick start guide (#1351) 2018-03-22 08:58:02 +01:00
416f03c05b Add light client spec 2018-03-21 10:00:18 +01:00
ced74251e9 maxPacketMsg -> packetMsgMax... 2018-03-21 02:47:38 +01:00
6c345f9fa2 First stab: p2p/conn 2018-03-21 02:27:10 +01:00
8c0c8e8e01 Merge pull request #1301 from tendermint/types-data+header+non-nil-panics
types: Hash invoked for nil Data and Header should not panic
2018-03-20 23:38:55 +01:00
79315efd1f Merge pull request #1341 from EugeneChung/develop
Remove unnecessary bytes.Compare() call
2018-03-20 16:27:06 +01:00
a61130aebb Remove unnecessary bytes.Compare() call 2018-03-20 23:43:18 +09:00
5a51a0ba06 Merge pull request #1337 from tendermint/1296-follow-up
Follow up for /health endpoint
2018-03-20 10:36:47 +01:00
0d0b56739d Merge pull request #1335 from tendermint/zarko/1146-improve-bft-time-spec
Improve BFT time spec
2018-03-20 01:00:34 +01:00
eb1816c9ff Merge pull request #1338 from tendermint/1266/xla-fix-flaky-testswitchreconnectstopersistentpeer
p2p: Keep reference to connections in test peer
2018-03-20 00:14:38 +01:00
50ae892d5e p2p: Keep reference to connections in test peer
We observed non-deterministic test failures in one of our switch tests,
which would happen if the GC would run between iterations of the accept
loop. As we don't hold any reference to the connection the setup
finalizer might get triggered and therefore the file handle closed. For
the curious check the references on finalizers and the variable scoping
in the spec:

https://groups.google.com/forum/#!topic/golang-nuts/xWkhGJ5PY6c
https://groups.google.com/forum/#!topic/golang-nuts/d8aF4rAob7U/discussion
https://golang.org/ref/spec#Declarations_and_scope

Fixes #1266
2018-03-19 20:35:12 +01:00
5a79b3d74a Improve the spec to make explicit median computation based on voting power 2018-03-19 19:10:02 +01:00
460599ef75 fix comment 2018-03-19 20:01:43 +03:00
830bb72d6f add Health method to clients
Refs #1296
2018-03-19 20:01:43 +03:00
b11c26cc1c update CHANGELOG 2018-03-19 19:53:28 +03:00
152290db7e Add \health rpc endpoint (#1306)
* Init `\health` rpc endpoint

* remove additional info from `\health` rpc endpoint

* Cleanup imports

* Added time threshold for health check

* Update rpc doc

* Remove unnecessary checks for blocktime creation lag

* Clean up of unnecessary config usage
2018-03-19 19:39:37 +03:00
20b198681b Merge pull request #1328 from tendermint/bucky/add-vote-readability
addVote readability
2018-03-19 12:24:28 +01:00
2bf106a1b3 Merge pull request #1333 from tendermint/1244-follow-up
consensus: fix tracking for MarkGood
2018-03-19 12:19:16 +01:00
2c445059f2 mark peer as good every blocksToContributeToBecomeGoodPeer blocks
if enough peers are marked good eventually some will become unmarked, so
good to have a force that will continue to cycle them back into good
territory!

Refs #1317
2018-03-19 14:10:25 +03:00
d8b08cd943 return back panic in peer#onReceive
Refs #1317
2018-03-19 13:19:05 +03:00
ab59f64f57 test we record votes and block parts
Refs #1317
2018-03-19 13:17:11 +03:00
42e3457884 fix tracking of votes and blockparts to not allow old information
also remove mutex
Refs #1317
2018-03-19 13:17:06 +03:00
31f3dd42e7 mark peer as good only once
or should we do it every N blocks?
Refs #1317
2018-03-19 13:17:00 +03:00
5fab8e404d replace magic number with blocksToContributeToBecomeGoodPeer const
Refs #1317
2018-03-19 13:16:56 +03:00
701df09971 do not use keywords
Refs #1317
2018-03-19 13:16:02 +03:00
d350da3135 config: fix private_peer_ids 2018-03-18 23:55:44 +01:00
ab7dea4f20 consensus: return from errors sooner in addVote 2018-03-18 23:09:04 +01:00
b297efb532 consensus: return from go-routine in test 2018-03-18 23:05:04 +01:00
eaabdb5cac Merge pull request #1282 from tendermint/1126-private-peers
private peers
2018-03-18 22:53:57 +01:00
066aee3045 Documentation: The character for 1/3 fraction could not be rendered in PDF on readthedocs. (#1326) 2018-03-18 22:44:38 +03:00
ff1ec0260e Merge pull request #1318 from tendermint/bucky/testnet-cmd-fix
testnet cmd: ensure config dir exists. closes #1290
2018-03-17 00:05:30 +01:00
7cb3188fbc testnet cmd: ensure config dir exists. closes #1290 2018-03-16 14:26:43 +01:00
9b9022f8df privVal: Improve SocketClient network code (#1315)
Follow-up to feedback from #1286, this change simplifies the connection
handling in the SocketClient and makes the communication via TCP more
robust. It introduces the tcpTimeoutListener to encapsulate accept and
i/o timeout handling as well as connection keep-alive, this type could
likely be upgraded to handle more fine-grained tuning of the tcp stack
(linger, nodelay, etc.) according to the properties we desire. The same
methods should be applied to the RemoteSigner which will be overhauled
when the priv_val_server is fleshed out.

* require private key
* simplify connect logic
* break out conn upgrades to tcpTimeoutListener
* extend test coverage and simplify component setup
2018-03-16 16:32:17 +04:00
68e049d3af Merge pull request #1244 from tendermint/1147-using-mark-good-and-stop-peer-for-error
Using MarkGood and StopPeerForError
2018-03-15 18:58:29 +01:00
86ddf17db0 add a todo
Refs #1281
2018-03-15 11:58:20 +04:00
a655500047 fix copy-pasted comment [ci skip] 2018-03-15 11:58:20 +04:00
714f885dac mark peer as good if it contributed enough votes or block parts
Refs #1147
2018-03-15 11:58:20 +04:00
b0d8f552c5 return err if peer has sent a vote that does not match our round 2018-03-15 11:58:20 +04:00
63cb69cb96 comment out ErrAddingVote because it breaks byzantine_test 2018-03-15 11:58:20 +04:00
266974cb59 stop peer if it sends invalid vote 2018-03-15 11:58:20 +04:00
bcf54b0aa3 PanicSanity is deprecated 2018-03-15 11:58:20 +04:00
d86855ad7a stop peer if it sends us msg with unknown channel 2018-03-15 11:58:20 +04:00
d0c67bbe16 stop peer if evidence is not valid 2018-03-15 11:58:20 +04:00
4242352852 stop peer on decoding error 2018-03-15 11:58:19 +04:00
f299689573 return back defaultChannelCapacity 2018-03-15 11:58:19 +04:00
baf457e6d4 return error if peer sent us a block we didn't expect with a height too far ahead/behind 2018-03-15 11:58:19 +04:00
0c7e871ef0 [blockchain] replace timeoutsCh with more abstract errorsCh 2018-03-15 11:58:19 +04:00
87ce804b4a cmn.PanicSanity is deprecated 2018-03-15 11:58:19 +04:00
2a258a2c3f revert removing private peers from persistent 2018-03-15 11:55:30 +04:00
a40518c7da revert adding dial_peers's private flag 2018-03-15 11:55:30 +04:00
31deaa4a79 fix broken merge 2018-03-15 11:55:30 +04:00
736ea055a8 add a test for pex reactor 2018-03-15 11:55:30 +04:00
a39aec0bae rename private_peers to private_peer_ids to distinguish from peers 2018-03-15 11:55:30 +04:00
8bef3eb1f4 private peers
Refs #1126
2018-03-15 11:55:29 +04:00
244d88dfda Merge pull request #1314 from tendermint/add-go-amino-as-source-to-wire
Add go amino as source to wire
2018-03-15 01:10:38 +01:00
76e1dd41e4 fix Makefile's .PHONY 2018-03-14 21:42:35 +04:00
e39187a063 add go-amino as source for go-wire 2018-03-14 21:42:17 +04:00
cd2ba4aa7f Merge pull request #1286 from tendermint/feature/xla-priv-val-invert-dial
Invert privVal socket communication
2018-03-12 16:49:32 +01:00
0de19420f6 cmd/tendermint/commands/lite: add tcp scheme to address URLs (#1297)
Noticed while investigating
https://github.com/tendermint/tendermint/issues/970

As reported by @zramsay, we'd get the warning
from tendermint/rpc/lib because we were passing in
scheme-less addresses, so by default use "tcp".

Also by default, "node" (nodeAddr) has been set to:
  "tcp://localhost:46657"
instead of the bare:
  "localhost:46657"

This change is just to clean up such warnings as
they spuriously would spook users for a package "lite"
that claims to be secure.
2018-03-12 10:03:11 +04:00
f3000d0c84 Merge pull request #1292 from tendermint/1125-exp-backoff-for-ensure-peers
exponential backoff for addrs in the address book
2018-03-11 19:57:49 +01:00
fc5b0471d9 use time.Since 2018-03-11 14:13:34 +04:00
264bce4ddd skip dialing based on last time dialed 2018-03-11 14:00:49 +04:00
0f41570c80 fixes from bucky's review 2018-03-11 13:22:37 +04:00
8723c91db9 types: Hash invoked for nil Data and Header should not panic
Fixes https://github.com/tendermint/tendermint/issues/1298
Fixes https://github.com/tendermint/tendermint/issues/1299

Found while writing tests in https://github.com/tendermint/tendermint/pull/1300
2018-03-10 21:44:08 -08:00
f85c8896d9 test pex_reactor's dialPeer 2018-03-09 16:23:52 +04:00
f0d4f56327 refactor pex_reactor tests 2018-03-09 16:02:24 +04:00
3d5c05e4e6 Merge pull request #1293 from tendermint/update-template
add 2 more points to ISSUE_TEMPLATE
2018-03-09 15:15:34 +04:00
018da09f14 do not run complete test suite on make
bad dev experience
2018-03-08 18:55:14 +04:00
60a64af28d add 2 more points to ISSUE_TEMPLATE
Refs #1291
2018-03-08 18:53:11 +04:00
13a2013229 Testing refactor for Jenkins (#1098)
* de-mystify tests & run them in parallel (#1031)

* test optimization for jenkins (#1093)

* makefile cleanup

* tests: split fast and slow go tests, closes #1055

* pr comments

* restore circle conditions

* fix need_abci

* ...

* docker run: no :Z for circle?

* Remove cmd breaking comment
2018-03-08 18:52:38 +04:00
1941b5c769 fixes from @xla's review 2018-03-08 16:31:44 +04:00
21e2c41c6b exponential backoff for addrs in the address book
Refs #1125
2018-03-08 14:04:26 +04:00
589781721a Invert privVal socket communication
Follow-up to #1255 aligning with the expectation that the external
signing process connects to the node. The SocketClient will block on
start until one connection has been established, support for multiple
signers connected simultaneously is a planned future extension.

* SocketClient accepts connection
* PrivValSocketServer renamed to RemoteSigner
* extend tests
2018-03-07 12:37:05 +01:00
2ce57a65ff Merge pull request #1284 from tendermint/feature/xla-follow-priv-val
Follow-ups to PrivValidator
2018-03-06 23:37:10 +01:00
2aa77025c3 Fix typo 2018-03-06 19:56:31 +01:00
8e1856a90a Use builtin panic 2018-03-06 19:56:31 +01:00
ca619c80b6 Stop privVal socket client on node shutdown 2018-03-06 19:56:30 +01:00
25ff699425 Improve method docs 2018-03-06 19:55:26 +01:00
879b4c0a2c Use common method to determine file existence 2018-03-06 19:55:26 +01:00
45d07a3d0b Merge pull request #1283 from tendermint/feature/xla-run-integration-release
Speed up CircleCI builds
2018-03-06 19:38:08 +01:00
788354d81e fix typo (#1285) 2018-03-06 20:44:13 +04:00
b7ce89e568 Speed up CircleCI builds
To achieve faster feedback cycles for our feature PRs this change
reduces the average buildtime from 35 to ~6min by utilising their new
2.0 offering based on docker and nomad. We make use of parallel build
steps wherever possible so that the duration is determined by the
slowest test suite (p2p).

This is an intermediate step until we move our CI/CD completely
on-premise for more control and added security.
2018-03-06 17:36:44 +01:00
8d81a259c7 Merge pull request #1280 from tendermint/zach/explain-determinism
docs: add 'On Determinism'
2018-03-06 13:44:00 +04:00
3019761204 docs: add document 'On Determinism'
closes https://github.com/tendermint/abci/issues/56
2018-03-06 15:19:59 +08:00
6120a4c5e4 Merge pull request #1256 from tendermint/feature/more-priv-val
PrivValidatorAddr -> PrivValidatorListenAddr. Update ADR008
2018-03-05 21:48:16 +04:00
533ed2a876 adr: Amend decisions for PrivValidator 2018-03-05 17:38:05 +01:00
d4e4055d57 PrivValidatorAddr -> PrivValidatorListenAddr. Update ADR008 2018-03-05 17:11:43 +01:00
ee51ad8e29 Make RPC handler protocol agnostic (#1276) 2018-03-05 19:59:04 +04:00
bdd50c5f37 fix docs links & stuff (#1273)
* fix links in docs/spec etc, closes #1261

* spec: remove ref to non-existant repo

* codecov you weirdo
2018-03-05 16:30:36 +04:00
3d88612690 Merge pull request #1274 from tendermint/codecov
Codecov
2018-03-05 15:54:33 +04:00
630d54c95a return back threshold and ignore sections 2018-03-05 15:16:24 +04:00
3cedd8cf07 Merge pull request #1265 from tendermint/bucky/new-wire-api
Bucky/new wire api
2018-03-02 10:56:24 -05:00
929f326dd2 update dep 2018-03-02 10:59:10 -05:00
ff8c648c23 types: uncomment some tests 2018-03-02 09:26:37 -05:00
8bceb5ce36 Merge pull request #1233 from tendermint/feature/xla-dial-seed-without-timeout
p2p: if we have no peers we should dial seeds right away
2018-03-02 09:07:01 -05:00
8f2703e8b2 Dial seeds directly without potential peers
In order to improve the operator experience we want the node to dial
seeds immediately if there are no peers to connect to. Until now the
routine responsible for ensuring peers are connected to would wait
a random amount of time up to 30s (if not configured otherwise).
2018-03-02 12:55:01 +01:00
c394eef7b8 types: TestValidatorSetVerifyCommit 2018-03-02 04:21:23 -05:00
f9921ae362 types/validator_set_test: move funcs around 2018-03-02 03:52:44 -05:00
fff0c6cd8e Add app_state from genesis file in InitChain message 2018-03-02 03:46:04 -05:00
59872bf335 update dep for new go-wire API 2018-03-02 02:28:53 -05:00
656854186c state: fix txResult issue with UnmarshalBinary into ptr 2018-03-02 02:28:17 -05:00
6596bff8ec types: bring back json.Marshal/Unmarshal for genesis/priv_val 2018-03-02 02:09:28 -05:00
eaafd9d61c state: builds 2018-03-02 01:51:27 -05:00
5378bfc5c7 types.SignBytes -> o.SignBytes 2018-03-02 01:50:17 -05:00
abeeeeb611 types: fix validator_set_test issue with UnmarshalBinary into ptr 2018-03-02 01:49:59 -05:00
ca3655a409 types: p2pID -> P2PID 2018-03-02 01:42:56 -05:00
6cf5100645 types: working on tests... 2018-03-02 01:34:23 -05:00
51628aea08 types: revert to old wire. builds 2018-03-02 01:33:38 -05:00
3395f5fb0e types: builds 2018-03-02 01:28:38 -05:00
d2cd079541 types: tests build 2018-03-02 01:28:21 -05:00
fc35e3b8c5 wire: no codec yet 2018-03-02 01:27:52 -05:00
085b4f5f2e add wire pkg with global codec 2018-03-02 01:26:38 -05:00
fd58645dd2 types: remove dep on p2p 2018-03-02 01:26:03 -05:00
200787ede2 types: update for new go-wire. WriteSignBytes -> SignBytes 2018-03-02 01:25:54 -05:00
9cdba04fe9 Merge pull request #1142 from tendermint/add_valid_value_mechanism
Add support for ValidBlock mechanism for the simplest case
2018-03-01 23:33:46 -05:00
e92c87630d Merge pull request #1258 from tendermint/return-dummy-app
return back dummy & persistent_dummy as options for proxy_app
2018-03-01 15:14:07 +04:00
d4e93a6de3 Separate ValidBlock rule from unlocking rule 2018-03-01 11:42:22 +01:00
4670857c15 Add support for ValidBlock mechanism for the simplest case 2018-03-01 11:42:22 +01:00
e8d8aedd1f update changelog 2018-03-01 12:00:09 +04:00
87372da730 return back dummy & persistent_dummy as options for proxy_app 2018-03-01 11:54:08 +04:00
3b40b62d04 Merge pull request #1198 from tendermint/feature/genesisrawjson
SDK: AppOptions -> AppState
2018-03-01 00:55:13 +04:00
c41cbf2a07 add missing golang.org/x/net/netutil package 2018-02-28 23:44:18 +04:00
1a3faa8db1 add app_state field to docs 2018-02-28 23:44:10 +04:00
4ce79baac7 rename app_options to app_state in genesis_test 2018-02-28 23:44:10 +04:00
056b70b4ce update changelog 2018-02-28 23:44:10 +04:00
4806b3b9bf AppOptions -> AppStateJSON 2018-02-28 23:44:10 +04:00
2a8f0000b2 Merge pull request #1250 from tendermint/ditch-glide
Ditch glide
2018-02-28 09:52:12 -05:00
dd2d846c02 Merge pull request #1203 from tendermint/feature/priv_val
types/priv_validator package
2018-02-28 09:27:03 -05:00
2ae87eee4e style fixes from @xla 2018-02-28 12:24:26 +04:00
4be23027ed adding recipe for minimalistic deps analysis (#1218) 2018-02-28 11:23:31 +04:00
c19bbb2403 switch back to parsing .lock file 2018-02-28 11:15:40 +04:00
edb871f514 Merge pull request #1237 from tendermint/feature/priv_val_socket_client
privVal: Integrate socket client
2018-02-28 00:57:51 -05:00
9c5937df96 Merge pull request #1247 from tendermint/feature/xla-integrate-codecov
Integrate CodeCov as change acceptance stage
2018-02-28 00:38:37 -05:00
be6082df8e Merge pull request #1043 from tendermint/lite-binary-vs-linear-search+optimize-insertions
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders
2018-02-28 00:33:59 -05:00
66354de219 cd into tendermint before calling dep status 2018-02-27 18:47:53 +04:00
458a40f74e Integrate CodeCov as change acceptance stage
As a rough measure to keep quality up we want to integrate our code
coverage tooling to the point where it is required for changes to be
merged.

Example taken from https://github.com/cosmos/voyager/blob/develop/codecov.yaml
2018-02-27 15:39:28 +01:00
0821384ac6 update abci version 2018-02-27 18:34:32 +04:00
e01650f21d fix Dockerfile.develop 2018-02-27 18:02:40 +04:00
8dd06cf197 ditch glide 2018-02-27 18:02:40 +04:00
93732b4c1e remove old network tests
Refs #1249
2018-02-27 18:02:25 +04:00
2cc63069c6 rename dummy to kvstore (#1223)
* remove accidental binary

* docs: s/Dummy&dummy/KVStore&kvstore/g

* glide update to abci

* update abci import paths

* dummy begone, hello kvstore

* RequestInitChain needs genesisBytes

* glide update
2018-02-27 18:01:10 +04:00
6270ecef8c Switch to dep from glide for dependency management (#1243)
* Switch to dep from glide for dependency management

* Update CI dockerfile to use dep instead of glide

* Wrong file extension

* Run 'dep ensure' after copying code

* Install glide to handle abci dependencies in testing

* Use `dep ensure -vendor-only` to setup vendor directory before installing source code on ci
2018-02-27 15:59:50 +04:00
9293ae76bf p2p: introduce peerConn to simplify peer creation (#1226)
* expose AuthEnc in the P2P config

if AuthEnc is true, dialed peers must have a node ID in the address and
it must match the persistent pubkey from the secret handshake.

Refs #1157

* fixes after my own review

* fix docs

* fix build failure

```
p2p/pex/pex_reactor_test.go:288:88: cannot use seed.NodeInfo().NetAddress() (type *p2p.NetAddress) as type string in array or slice literal
```

* p2p: introduce peerConn to simplify peer creation

* Introduce `peerConn` containing the known fields of `peer`
* `peer` only created in `sw.addPeer` once handshake is complete and NodeInfo is checked
* Eliminates some mutable variables and makes the code flow better
* Simplifies the `newXxxPeer` funcs
* Use ID instead of PubKey where possible.
        * SetPubKeyFilter -> SetIDFilter
        * nodeInfo.Validate takes ID
        * remove peer.PubKey()

* persistent node ids

* fixes from review

* test: use ip_plus_id.sh more

* fix invalid memory panic during fast_sync test

```
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: panic: runtime error: invalid memory address or nil pointer dereference
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: [signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x98dd3e]
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]:
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: goroutine 3432 [running]:
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.newOutboundPeerConn(0xc423fd1380, 0xc420933e00, 0x1, 0x1239a60, 0
xc420128c40, 0x2, 0x42caf6, 0xc42001f300, 0xc422831d98, 0xc4227951c0, ...)
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/peer.go:123 +0x31e
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).addOutboundPeerWithConfig(0xc4200ad040, 0xc423fd1380, 0
xc420933e00, 0xc423f48801, 0x28, 0x2)
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:455 +0x12b
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).DialPeerWithAddress(0xc4200ad040, 0xc423fd1380, 0x1, 0x
0, 0x0)
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:371 +0xdc
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: github.com/tendermint/tendermint/p2p.(*Switch).reconnectToPeer(0xc4200ad040, 0x123e000, 0xc42007bb00)
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:290 +0x25f
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: created by github.com/tendermint/tendermint/p2p.(*Switch).StopPeerForError
2018-02-21T06:30:05Z box887.localdomain docker/local_testnet_4[14907]: #011/go/src/github.com/tendermint/tendermint/p2p/switch.go:256 +0x1b7
```
2018-02-27 15:54:40 +04:00
74d3f7e1fd Integrate private validator socket client
Following ADDR 008 the node will connect to an external
process to handle signing requests. Operation of the external process is
left to the user.

* introduce alias for PrivValidator interface on socket client
* integrate socket client in node
* structure tests
* remove unnecessary flag
2018-02-23 13:58:22 +01:00
2fd023a239 remove accidental binary 2018-02-21 00:04:53 -05:00
c8a2bdf78b Merge pull request #1225 from tendermint/release-v0.16.0
Release v0.16.0
2018-02-20 23:23:48 -05:00
3cd604562c RequestInitChain needs genesisBytes 2018-02-21 03:43:47 +00:00
7c6c0dba53 glide update 2018-02-21 03:32:02 +00:00
ec2f3f49ef changelog date and version 2018-02-19 17:35:46 -05:00
8bba7c64bc update version and changelog [ci skip] 2018-02-19 17:33:48 -05:00
ffd2483e67 Merge pull request #1204 from tendermint/feature/priv_val_sockets
Feature/priv val sockets
2018-02-19 16:06:07 -05:00
0467de890a Merge pull request #1202 from tendermint/restore-mempool-memory-leak-tests
restore mempool memory leak tests
2018-02-19 15:36:19 -05:00
0ae0155cba restore mempool memory leak tests 2018-02-19 15:34:33 -05:00
f4feb7703b fix appHash log. closes #1207 2018-02-19 15:32:09 -05:00
a14aab67de Integrate PrivValidator socket server 2018-02-19 19:20:01 +01:00
106d804357 Correct config description 2018-02-14 02:51:05 +01:00
a1020307a0 Clean up flags 2018-02-14 02:41:16 +01:00
6c70b4ce05 Apply connection deadline consistently 2018-02-14 02:25:17 +01:00
2a292efb56 Return error for all PrivValidator methoods
As calls to the private validator can involve side-effects like network
communication it is desirable for all methods returning an error to not
break the control flow of the caller.

* adjust PrivValidator interface
2018-02-13 19:34:50 +01:00
82b1a34a36 Separate connect logic
* break out connect functionality out of OnStart
* introduce max retries
2018-02-13 19:08:21 +01:00
0e68638af3 update glide abci/tmlibs to develop 2018-02-12 19:13:36 -05:00
d3e276bf80 Merge pull request #1209 from tendermint/1205-fixes-for-p2p-memory-leak-and-pong
Fixes for p2p memory leak and pong
2018-02-12 19:04:31 -05:00
fc585bcdec do not block when writing to pongTimeoutCh
Refs #1205
2018-02-12 17:04:07 +04:00
2a24ae90c1 fixes from Jae's review
1. remove pointer
2. add Quit() method to Service interface
2018-02-12 14:32:09 +04:00
8da2a6a147 types/priv_validator: fixes for latest p2p and cmn 2018-02-09 17:24:30 -05:00
7d71e702d8 Integrate privVal client with node secret 2018-02-09 16:54:43 -05:00
38d18ca11a Harden tests 2018-02-09 16:53:17 -05:00
32d9563a15 Format and consolidate 2018-02-09 16:53:17 -05:00
18f7e52562 Use secret connection 2018-02-09 16:53:17 -05:00
fec541373d Correct server protocol 2018-02-09 16:53:17 -05:00
ff600e9aa0 wip: check error of wire read 2018-02-09 16:53:17 -05:00
a49357b19e wip: Avoid underscore in var name 2018-02-09 16:53:17 -05:00
4b997c29ee wip: fix nil pointer deference 2018-02-09 16:53:17 -05:00
d321839669 wip: fix code block in ADR 2018-02-09 16:53:17 -05:00
c27fda09dd wip: Comment types
* add comments to all public types
* fix comments to adhere to comment standards
2018-02-09 16:53:15 -05:00
23eb84db35 wip: priv val via sockets 2018-02-09 16:52:58 -05:00
bef91ea7fe adr-008-priv-validator 2018-02-09 16:52:05 -05:00
459633fb4c types/priv_validator 2018-02-09 16:38:23 -05:00
f1c8489270 Merge pull request #1201 from tendermint/1022-do-not-enforce-1/3-val-changes
do not enforce 1/3 validator power change
2018-02-09 16:15:38 -05:00
2d10c8f15b Merge pull request #1095 from tendermint/804-p2p-issues
[p2p] Pong Timeout
2018-02-09 14:38:24 -05:00
106cdb74e5 do not enforce 1/3 validator power change
leave it to the app

Refs #1022
2018-02-09 23:30:04 +04:00
22b038810a do not block in recvRoutine 2018-02-09 23:03:26 +04:00
45750e1b29 fix race by sending signal instead of stopping pongTimer 2018-02-09 21:32:29 +04:00
26419fba28 refactor code plus add one more test
* extract stopPongTimer method
* TestMConnectionMultiplePings
2018-02-09 21:32:29 +04:00
ac0123d249 drain pongTimeoutCh and pongTimer's channel to prevent leaks 2018-02-09 21:32:29 +04:00
f4ff66de30 rewrite pong timer to use time.AfterFunc 2018-02-09 21:32:29 +04:00
747b73cb95 fix merge conflicts 2018-02-09 21:32:29 +04:00
161e100a24 close return channel when we're done
Benchmark results:

```
BenchmarkSwitchBroadcast-2         30000             71275 ns/op
--- BENCH: BenchmarkSwitchBroadcast-2
        switch_test.go:339: success: 1, failure: 0
        switch_test.go:339: success: 100, failure: 0
        switch_test.go:339: success: 10000, failure: 0
        switch_test.go:339: success: 30000, failure: 0
```
2018-02-09 21:32:29 +04:00
3ae738f453 increase timeouts 2018-02-09 21:32:29 +04:00
d14d4a2527 remove TryBroadcast 2018-02-09 21:32:29 +04:00
860da464df remove weird concurrency testing 2018-02-09 21:32:28 +04:00
4e2000abfe control order by sending msgs from one goroutine 2018-02-09 21:32:28 +04:00
5834a59816 read ping 2018-02-09 21:32:28 +04:00
b28b76ddf7 rename pingTimeout to pingInterval, pongTimer is now time.Timer 2018-02-09 21:32:28 +04:00
91e4f4b786 ping/pong timeout in config 2018-02-09 21:32:28 +04:00
9b554fb2c4 switch test modification 2018-02-09 21:32:28 +04:00
f97ead4f5f prep for merge 2018-02-09 21:32:28 +04:00
5af22d6ee6 remove SwitchEventNewPeer, SwitchEventDonePeer 2018-02-09 21:32:28 +04:00
1d16df6a92 add test, TrySend in broadcast 2018-02-09 21:32:27 +04:00
e7bc946760 Merge pull request #1200 from tendermint/update-deps
Update tmlibs & protobuf deps
2018-02-09 11:00:43 -05:00
cf1e1f5899 Merge pull request #1194 from tendermint/1177-semantics-of-currate-low-msg
improve "curRate too low" message
2018-02-09 11:00:09 -05:00
2f8372d629 update protobuf 2018-02-09 13:58:36 +04:00
d84e4effce update tmlibs 2018-02-09 13:47:51 +04:00
0c1b91b762 revert back curRate != 0 2018-02-09 13:02:44 +04:00
c8990d06d9 remove curRate != 0 2018-02-09 12:01:13 +04:00
b0a55882b2 lower the minRecvRate
See https://github.com/tendermint/tendermint/issues/1177#issuecomment-363720118
2018-02-09 12:01:12 +04:00
d1fa44e816 improve "curRate too low" message
Refs #1177

Note on labels:
KB - 1024
kB - 1000
https://ux.stackexchange.com/questions/13815/files-size-units-kib-vs-kb-vs-kb
2018-02-09 12:01:12 +04:00
199ea40980 Merge pull request #1196 from tendermint/1149-TestReactorValidatorSetChanges-fails-non-deterministically
WIP: TestReactorValidatorSetChanges fails non deterministically
2018-02-09 01:51:17 -05:00
66fc476e1e Merge pull request #1173 from tendermint/memory-leak-in-reconnect-to-peer-2
fix memory leak in mempool reactor
2018-02-09 01:50:34 -05:00
6b347200d9 Merge pull request #1197 from tendermint/1155-seed-mode-flag
add seed_mode flag (`--p2p.seed_mode`)
2018-02-08 17:48:39 -05:00
8a908a7cf9 Merge pull request #1193 from tendermint/return-back-cmd-logging
With must be called on log.filter, otherwise "main" entries get filtered
2018-02-08 16:30:29 -05:00
0bcc11c9bc Merge pull request #1191 from tendermint/event-buffer-slice-clearing-on-flush
types: TxEventBuffer.Flush now uses capacity preserving slice clearing idiom
2018-02-08 16:28:47 -05:00
0247a21a93 Merge pull request #1086 from tendermint/966-deterministic-tooling-for-releases
Distribution improvements (freeze glide version + get rid of gox)
2018-02-08 15:26:11 -05:00
cf1f483526 add seed_mode flag (--p2p.seed_mode) 2018-02-08 17:20:55 +04:00
3f9aa8d8fa document that msgBytes in p2p/connection change 2018-02-08 13:25:26 +04:00
d6d1f8512d do not reset pingTimer
don't bother with this "only ping when we havent heard from them". lets
just always ping every peer from the sendRoutine every 10s no matter
what. if they dont pong within pongTimeout, disconnect :)
2018-02-08 13:08:11 +04:00
2b2c233977 write docs for Reactor interface 2018-02-08 13:07:40 +04:00
7640e6a29f add some p2p TODOs 2018-02-08 12:46:04 +04:00
b0ca8a0872 With must be called on log.filter, otherwise "main" entries get filtered
Also, we should allow "main" module to log INFO messages like

```
I[02-07|07:57:25.074] Found private validator                      module=main path=/home/vagrant/.tendermint/config/priv_validator.json
I[02-07|07:57:25.076] Found genesis file                           module=main path=/home/vagrant/.tendermint/config/genesis.json
```

Refs https://github.com/cosmos/gaia/issues/118

**BEFORE**:
```
$ tendermint init

```

**AFTER**:
```
$ tendermint init
I[02-07|07:57:25.074] Found private validator                      module=main path=/home/vagrant/.tendermint/config/priv_validator.json
I[02-07|07:57:25.076] Found genesis file                           module=main path=/home/vagrant/.tendermint/config/genesis.json
```
2018-02-07 12:08:13 +04:00
9e767771fc Merge pull request #1188 from ltfschoen/patch-1
Update getting-started.rst with Python 3 example
2018-02-06 12:53:47 -05:00
6c8d7a8c19 deterministic tooling for releases
get rid of gox

build target builds inside docker, dev-build - locally

Revert "build target builds inside docker, dev-build - locally"

This reverts commit 8ba89d5e8c5668e3839ff49952a9166d1158f6e8.

add build tags to make build/build_race/install

use tendermint's fork of glide instead of tar.gz

remove TMHOME unused var + set length for git hash

get rid of GOTOOLS_CHECK

fixes after review

zip

needed for distribution
2018-02-06 12:46:13 +04:00
15ef57c6d0 types: TxEventBuffer.Flush now uses capacity preserving slice clearing idiom
Fixes https://github.com/tendermint/tendermint/issues/1189

For every TxEventBuffer.Flush() invoking, we were invoking
a:
  b.events = make([]EventDataTx, 0, b.capacity)
whose intention is to innocently clear the events slice but
maintain the underlying capacity.

However, unfortunately this is memory and garbage collection intensive
which is linear in the number of events added. If an attack had access
to our code somehow, invoking .Flush() in tight loops would be a sure
way to cause huge GC pressure, and say if they added about 1e9
events maliciously, every Flush() would take at least 3.2seconds
which is enough to now control our application.

The new using of the capacity preserving slice clearing idiom
takes a constant time regardless of the number of elements with zero
allocations so we are killing many birds with one stone i.e
  b.events = b.events[:0]

For benchmarking results, please see
https://gist.github.com/odeke-em/532c14ab67d71c9c0b95518a7a526058
for a reference on how things can get out of hand easily.
2018-02-05 23:34:15 -08:00
f37c502fd8 Update getting-started.rst with Python 3 example 2018-02-06 16:00:51 +11:00
945b0e6eca cleanup glide.yaml 2018-02-05 22:53:44 +04:00
84a0a1987c comment out tests for now
https://github.com/tendermint/tendermint/pull/1173#issuecomment-363173047
2018-02-05 22:26:14 +04:00
11b68f1934 rewrite broadcastTxRoutine to use channels
https://play.golang.org/p/gN21yO9IRs3

```
func waitWithCancel(f func() *clist.CElement, ctx context.Context) *clist.CElement {
	el := make(chan *clist.CElement, 1)
	select {
	case el <- f():
```
will just run f() blockingly, so this doesn't change much in terms of behavior.
2018-02-05 16:36:26 +04:00
202d9a2c0c fix memory leak in mempool reactor
Leaking goroutine:
```
114 @ 0x42f2bc 0x42f3ae 0x440794 0x4403b9 0x468002 0x9fe32d 0x9ff78f 0xa025ed 0x45e571
```

Explanation:
it blocks on an empty clist forever. so unless theres txs coming in,
this go routine will just sit there, holding onto the peer too.
if we're constantly reconnecting to some peer, old instances are not
garbage collected, leading to memory leak.

Fixes https://github.com/cosmos/gaia/issues/108
Previous attempt https://github.com/tendermint/tendermint/pull/1156
2018-02-05 13:52:18 +04:00
bf84e82577 Merge pull request #1184 from tendermint/sdk2-tmlibs-abci
Updates for tmlibs and abci (sdk2)
2018-02-03 10:45:54 -05:00
abca9a2d61 woops - bring back glide.lock file 2018-02-03 03:59:16 -05:00
d34286c421 minor fixes - tests pass 2018-02-03 03:54:49 -05:00
bb2bdbc0e1 add missing element (tag.Value) to keyForTag
encoded as %s. not sure this will work with raw bytes
2018-02-03 03:52:25 -05:00
e7747f7d66 it compiles 2018-02-03 03:52:17 -05:00
7a5060dc52 replace data.Bytes with cmn.HexBytes 2018-02-03 03:47:01 -05:00
426379dc47 remove use of wire/nowriter 2018-02-03 03:39:14 -05:00
cd0fd06b0d update for sdk2 libs. need to fix kv test
NOTE we only updating for tmlibs and abci
2018-02-03 03:35:02 -05:00
4e3488c677 update types 2018-02-03 03:23:10 -05:00
061ad355bb update glide 2018-02-03 03:22:56 -05:00
2679b7554b lite: comment out iavl code - TODO #1183 2018-02-03 03:02:49 -05:00
62c9cad484 Merge pull request #1180 from tendermint/1146-add-BFT-time-spec
Add BFT time spec
2018-02-01 16:38:05 -05:00
4cbdbbaac9 Add BFT time spec 2018-02-01 15:22:08 +01:00
9ed296ae71 GetByHeight switches between linear & binary search on >=50 items
* GetByHeight will now switch to using binary search once
we have  >=50 items.
* Feedback from @ebuchman to catch a missed spot where
we forgot about lazy sorting that the original code
assumed would always have sorted commits by height.
Added a lazy sorting routine here too.
A test as well to ensure that we always get the properly
sorted and last value.
2018-01-31 20:53:03 -07:00
e8d0960cef nolint 2018-01-31 20:52:12 -07:00
2023115ff8 lite: TestCacheGetsBestHeight with GetByHeight and GetByHeightBinarySearch
Addressing PR review requests from @melekes and @ebuchman to
add a test that checks that the heights returned from both are
the same thus providing a perceptible equivalence of the code
linear range search vs binary range search code.
2018-01-31 20:52:12 -07:00
7790ae9e6f Fix spelling mistake 2018-01-31 20:52:12 -07:00
206da7a1b8 lite: < len(v) in for loop check, as per @melekes' recommendation
Also lazily load the commits to only be run once when
the benchmarks are activated, lest it slows down all the tests
2018-01-31 20:52:11 -07:00
14eaba9ec3 lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders
Updates #1021

* Implement a GetHeightBinarySearch method that looks for
the height using the binary search algorithm guaranteeing
worst case iteration time of O(log2(n))
whereas
worst case iteration time of O(n) for the current linear search

So if n we had 500 commits stored by height and sorted, to
trigger the worst case scenario for each, pass in
the most negative height you can find e.g. -1
Linear search: 500 iterations
Binary search: 9 iterations

with n=1000, qHeight = -1
Linear search: 1000 iterations
Binary search: 10 iterations

with n=1e6, qHeight = -1
Linear search: 1e6 iterations
Binary search: 20 iterations

Of course there are realistic expectations e.g. a max of
commits that may be saved so linear search might be useful
for very small size set because it has less preparing overhead
and only ~2 types of comparisons, but nonetheless binary search
shines as soon as we start to hit say 50 commits to search from
as you can see below:

```shell
$ go test -v -run=^$ -bench=MemStore
goos: darwin
goarch: amd64
pkg: github.com/tendermint/tendermint/lite
BenchmarkMemStoreProviderGetByHeightLinearSearch5-4     300000        6491 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightLinearSearch50-4      200000       12064 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightLinearSearch100-4      50000       32987 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightLinearSearch500-4       5000      395521 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4	       500     2940724 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch5-4     300000        6281 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch50-4      200000       10117 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch100-4     100000       18447 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch500-4      20000       89029 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4	      5000      265719 ns/op      1600 B/op       15 allocs/op
PASS
ok    github.com/tendermint/tendermint/lite 86.614s
$ go test -v -run=^$ -bench=MemStore
goos: darwin
goarch: amd64
pkg: github.com/tendermint/tendermint/lite
BenchmarkMemStoreProviderGetByHeightLinearSearch5-4     300000        6779 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightLinearSearch50-4      100000       12980 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightLinearSearch100-4      30000       43598 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightLinearSearch500-4       5000      377462 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4	       500     3278122 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch5-4     300000        7084 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch50-4      200000        9852 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch100-4     100000       19020 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch500-4      20000       99463 ns/op      1600 B/op       15 allocs/op
BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4	      5000      259293 ns/op      1600 B/op       15 allocs/op
PASS
ok    github.com/tendermint/tendermint/lite 86.204s
```

which gives
```shell
$ benchstat old.txt new.txt
name                               old time/op    new time/op    delta
MemStoreProviderGetByHeight5-4       6.63µs ± 2%    6.68µs ± 6%   ~             (p=1.000 n=2+2)
MemStoreProviderGetByHeight50-4      12.5µs ± 4%    10.0µs ± 1%   ~             (p=0.333 n=2+2)
MemStoreProviderGetByHeight100-4     38.3µs ±14%    18.7µs ± 2%   ~             (p=0.333 n=2+2)
MemStoreProviderGetByHeight500-4      386µs ± 2%      94µs ± 6%   ~             (p=0.333 n=2+2)
MemStoreProviderGetByHeight1000-4    3.11ms ± 5%    0.26ms ± 1%   ~             (p=0.333 n=2+2)
```

If need be we can make a hybrid algorithm that switches between the
linear and binary search depending on the number of items.
This is reminiscent of Python's TimSort algorithm.
2018-01-31 20:52:11 -07:00
2919bc3f7f Merge pull request #1178 from tendermint/nice-err-msg
improve error message
2018-01-31 21:32:58 -05:00
1c01671ec6 improve vague error msg, closes #1158 2018-01-31 17:44:19 +00:00
fe632ea32a spec: minor fixes 2018-01-26 17:26:33 -05:00
5b368252ac spec: more fixes 2018-01-26 17:26:33 -05:00
8cca953590 spec: remove notes, see #1152 2018-01-26 17:26:33 -05:00
4b4a2029c4 spec: typos & other fixes 2018-01-26 17:26:33 -05:00
6aa85357b6 Merge pull request #1160 from shapeshed/patch-1
Fix documentation typos
2018-01-26 17:17:43 -05:00
eae62ec09b Merge branch 'develop' into patch-1 2018-01-26 17:17:28 -05:00
18d96266bc Merge pull request #1140 from tendermint/feature/vagrant
Fix Vagrantfile
2018-01-26 17:12:06 -05:00
4529fd6787 Fix documentation typos 2018-01-26 14:44:48 +00:00
4a99a2a07d update contributing.md 2018-01-26 01:18:33 -05:00
4b63b3aa0b Switch to correct directory in Vagrant 2018-01-26 01:16:07 -05:00
fc860c3a07 Final Vagrantfile 2018-01-26 01:16:07 -05:00
2f147ec000 Remove upgrade step 2018-01-26 01:16:07 -05:00
0a7a190cd1 Fix vagrantfile
If you get an error, please run `vagrant box update`.
2018-01-26 01:16:07 -05:00
3366dfe32a Merge pull request #1151 from tendermint/fix/p2p-stop-conn
p2p/conn: fix blocking on pong during quit and break out of loops
2018-01-25 02:45:06 -05:00
baff4bd8cc p2p/conn: better handling for some stop conditions 2018-01-25 02:11:16 -05:00
fb109db33d update changelog 2018-01-25 02:10:01 -05:00
2f5971532e Merge pull request #1154 from tendermint/fix/consensus-tests
consensus: fix SetLogger in tests
2018-01-25 02:07:20 -05:00
ab13806276 consensus: print go routines in failed test 2018-01-25 01:22:53 -05:00
3ae26bd6e6 consensus: fix SetLogger in tests 2018-01-24 23:34:57 -05:00
27ef3489a0 Merge pull request #1049 from tendermint/p2p-channels
p2p: add Channels to NodeInfo and don't send for unknown channels
2018-01-24 15:29:38 -05:00
b6eb275b22 p2p: fix break in double loop 2018-01-24 14:27:37 -05:00
57cc8ab977 Merge pull request #1143 from tendermint/1091-race-condition
call FlushSync before calling CommitSync
2018-01-24 14:22:43 -05:00
99034904f8 p2p: fix tests for required channels 2018-01-23 23:45:51 -05:00
a0ffcbcee4 Merge pull request #1137 from tendermint/docs-consolidate
WIP: docs consolidation
2018-01-23 23:45:20 -05:00
260affd037 docs consolidation 2018-01-23 23:46:28 -05:00
d7b1b8d3d5 Merge pull request #1129 from tendermint/addrbook
p2p: bust up into sub dirs
2018-01-23 23:10:50 -05:00
50129ad8ac p2p: add Channels to NodeInfo and don't send for unknown channels 2018-01-23 22:43:56 -05:00
5c9cb5e6a2 Merge pull request #1133 from tendermint/fix/stop-peer-for-error
StopPeerForError in blockchain and consensus
2018-01-23 22:26:52 -05:00
4051391039 blockchain: test wip for hard to test functionality [ci skip] 2018-01-23 22:27:33 -05:00
8f3bd3f209 p2p: addrBook.Save() on DialPeersAsync 2018-01-23 22:25:39 -05:00
85816877c6 config: fix addrbook path to go in config 2018-01-23 22:21:17 -05:00
87087b8acd consensus: minor cosmetic 2018-01-23 21:41:13 -05:00
775bb85efb p2p/pex: wait to connect to all peers in reactor test 2018-01-23 21:30:53 -05:00
21ce5856b3 p2p: notes about ListenAddr 2018-01-23 21:26:19 -05:00
f5226e0008 Merge pull request #1144 from tendermint/create-logs-tarball
mercy for developers with slow Internet
2018-01-23 12:47:45 -05:00
a745fe2eed mercy for developers with slow Internet 2018-01-23 20:37:38 +04:00
5f3048bd09 call FlushSync before calling CommitSync
if we call it after, we might receive a "fresh" transaction from
  `broadcast_tx_sync` before old transactions (which were not
  committed).

Refs #1091

```
Commit is called with a lock on the mempool, meaning no calls to CheckTx
can start. However, since CheckTx is called async in the mempool
connection, some CheckTx might have already "sailed", when the lock is
released in the mempool and Commit proceeds.

Then, that spurious CheckTx has not yet "begun" in the ABCI app (stuck
in transport?). Instead, ABCI app manages to start to process the
Commit. Next, the spurious, "sailed" CheckTx happens in the wrong place.
```
2018-01-23 16:56:14 +04:00
6a5818e107 Merge pull request #1138 from tendermint/small-fix
Small fix in example
2018-01-22 17:27:35 -05:00
dfdfd6c98e Small fix in example 2018-01-22 13:10:54 +01:00
3090b05eb4 p2p: use conn.Close when peer is nil 2018-01-21 16:26:59 -05:00
ee674f919f StopPeerForError in blockchain and consensus 2018-01-21 13:32:04 -05:00
813bb6af96 Merge pull request #1092 from tendermint/add-consensus-reactor-doc
Add consensus reactor doc
2018-01-21 12:40:28 -05:00
aecbff725f Merge pull request #1082 from tendermint/document-proposer-selection
Document proposer selection procedure
2018-01-21 12:39:43 -05:00
6679fef2be Merge pull request #1056 from tendermint/feature/mempool-spec
WIP: Mempool specification
2018-01-21 12:39:10 -05:00
c070ed056a Merge pull request #1051 from tendermint/feature/blockchain_reactor_docs
docs: Blockchain Reactor Documentation
2018-01-21 12:38:32 -05:00
2c6ed302b7 minor changes [ci skip] 2018-01-21 12:36:46 -05:00
0eb85161aa More specification 2018-01-21 12:35:09 -05:00
940145b368 Bullet points for reactor and poolRoutine 2018-01-21 12:32:45 -05:00
a30315276b Formatting and documentation 2018-01-21 12:32:23 -05:00
6366eb9d99 Cleanup build and structure 2018-01-21 12:31:14 -05:00
44e967184a p2p: tmconn->conn and types->p2p 2018-01-21 00:34:41 -05:00
2ec425ae4b Merge pull request #1128 from tendermint/862-seed-crawler-mode
seed crawler mode
2018-01-20 23:35:26 -05:00
0d7d16005a fixes 2018-01-20 21:44:30 -05:00
5b5cbaa66a p2p: use sub dirs 2018-01-20 21:35:37 -05:00
03550c7076 wip addrbook 2018-01-20 21:33:43 -05:00
930fde056a p2p: add back lost func 2018-01-20 21:28:00 -05:00
8d758560d8 p2p/trustmetric: non-deterministic test 2018-01-20 21:24:22 -05:00
7b87cdaed8 p2p: seed disconnects after sending addrs 2018-01-20 21:24:22 -05:00
c2f97e6454 p2p: seed mode fixes from rebase and review 2018-01-20 21:24:22 -05:00
88eb3e7af0 some minor renames 2018-01-20 21:24:20 -05:00
949211a137 added a test for PEX reactor seed mode 2018-01-20 21:23:48 -05:00
39d8da3536 docs: update getting started [ci skip] 2018-01-20 21:21:50 -05:00
ae27e85bf7 add warnings about new spec 2018-01-20 21:20:15 -05:00
f2d19162d2 fixes from caffix review 2018-01-20 21:20:09 -05:00
d36e118bf6 Add Consensus reactor spec 2018-01-19 19:57:08 +01:00
02c1aef48b Merge pull request #1121 from tendermint/consensus-tests
Consensus tests
2018-01-19 12:50:32 -05:00
6f3d9b4be3 fix race 2018-01-19 01:36:52 -05:00
f06cc6630b mempool: cfg.CacheSize and expose InitWAL 2018-01-19 01:03:03 -05:00
8171628ee5 make tests run faster 2018-01-19 00:59:09 -05:00
1cb76625d3 consensus: rename test funcs 2018-01-19 00:59:09 -05:00
ebeadfc57e dont run metalinter 2018-01-19 00:58:54 -05:00
cca597a9c0 fix and test config file 2018-01-19 00:08:19 -05:00
940db715f4 Merge pull request #1104 from tendermint/p2p-consolidate
WIP: P2P consolidate
2018-01-18 19:00:35 -05:00
ec2b038493 Merge pull request #1103 from tendermint/1100-document-event-subscriptions
document event subscriptions
2018-01-18 19:00:01 -05:00
ba0cb4f10e Merge pull request #1115 from tendermint/docs-tx-format
document tx formats
2018-01-18 18:57:23 -05:00
e764a180d8 docs: fix tx formats [ci skip] 2018-01-18 18:58:33 -05:00
bc19e7843c Merge branch 'develop' into p2p-consolidate 2018-01-18 18:30:37 -05:00
f57f97c4bd fix bash tests 2018-01-18 17:40:12 -05:00
b32474bb1a Merge pull request #1116 from tendermint/feature/prs
Create PULL_REQUEST_TEMPLATE.md
2018-01-18 13:52:18 -05:00
0a20e8f268 Create PULL_REQUEST_TEMPLATE.md 2018-01-18 13:53:18 -05:00
9d4d939b89 docs: tx formats: closes #1083, #536 2018-01-18 15:37:56 +00:00
c1e6e73bb1 Merge pull request #1108 from tendermint/zramsay-patch-1
Update p2p README
2018-01-15 10:31:31 -05:00
620c957a44 fix test 2018-01-14 13:24:43 -05:00
64ce7eef16 Merge pull request #1107 from tendermint/p2p-pex-abuse
better abuse handling in pex
2018-01-14 13:03:02 -05:00
fc7915ab4c fixes from review 2018-01-14 13:03:57 -05:00
26aaa283a9 p2p: remove deprecated Dockerfile 2018-01-14 13:51:28 +00:00
a29c67563c Update p2p README, closes #1102 2018-01-14 13:50:34 +00:00
17f7a9b510 improve seed dialing logic 2018-01-14 03:56:15 -05:00
3df5fd21cd better abuse handling in pex 2018-01-14 03:22:01 -05:00
99076f1942 Merge pull request #1105 from tendermint/p2p-switch
cleanup switch
2018-01-14 01:20:13 -05:00
3368eeb03e fix tests 2018-01-14 01:19:07 -05:00
68237911ba NetAddress.Same checks ID or DialString 2018-01-14 01:15:37 -05:00
f9e4f6eb6b reorder peer.go methods 2018-01-14 01:15:37 -05:00
8b74a8d6ac NodeInfo not a pointer 2018-01-14 01:15:33 -05:00
08f84cd712 a little more moving around 2018-01-13 23:56:57 -05:00
452d10f368 cleanup switch 2018-01-13 17:37:52 -05:00
8b3fb743cf Merge pull request #1048 from tendermint/p2p-id
P2P ID
2018-01-13 17:35:21 -05:00
7667e11973 remove RemoteAddr from NodeInfo 2018-01-13 17:36:03 -05:00
53a5498fc5 more fixes from review 2018-01-13 17:34:12 -05:00
e4d52401cf some fixes from review 2018-01-13 16:06:51 -05:00
9670519a21 remove PoW from ID 2018-01-13 15:50:59 -05:00
b1485b181a Merge branch 'p2p-consolidate' into p2p-id 2018-01-13 15:20:23 -05:00
47a6928890 Merge pull request #1030 from tendermint/864-distinguish-between-seeds-and-manual-peers
Distinguish between seeds and manual peers
2018-01-13 15:12:47 -05:00
c1e167e330 note in trust metric test 2018-01-13 15:11:13 -05:00
e2b3b5b58c dial_persistent_peers -> dial_peers with persistent option 2018-01-13 14:50:58 -05:00
e6b70baae0 Merge branch 'develop' into 864-distinguish-between-seeds-and-manual-peers 2018-01-13 14:34:32 -05:00
b40aa91b41 document event subscriptions
Refs #1100
2018-01-12 12:53:34 -06:00
a13b17ec6c Merge pull request #792 from tendermint/config
Config Improvements
2018-01-10 14:41:30 -05:00
b32a507a1b Merge pull request #1088 from tendermint/1087-update-docker
Update docker image
2018-01-10 14:23:06 -05:00
d6e01e8cee Merge pull request #1089 from tendermint/1075-document-underflow-overflow
document the maximum supported voting power due to overflow [ci skip]
2018-01-10 14:20:31 -05:00
c79ba3c349 document the maximum supported voting power due to overflow [ci skip]
Refs #1075
2018-01-10 14:21:26 -05:00
12ca972761 Merge branch 'develop' into 1087-update-docker 2018-01-10 11:08:14 -06:00
657ad214cb p2p tests: put priv_val in right place 2018-01-10 16:30:00 +00:00
39acf1c5e8 Merge branch 'develop' into config 2018-01-10 14:21:24 +00:00
075ae1e301 minimal test for dialing seeds in pex reactor 2018-01-09 18:29:29 -06:00
705d51aa42 move dialSeedsIfAddrBookIsEmptyOrPEXFailedToConnect into PEX reactor 2018-01-09 17:54:29 -06:00
ef0493ddf3 rewrite Peers section of Using Tendermint guide [ci skip] 2018-01-09 17:54:28 -06:00
1b455883d2 readd /dial_seeds 2018-01-09 17:54:28 -06:00
e4897b7bdd rename manual peers to persistent peers 2018-01-09 16:18:05 -06:00
37f86f9518 update changelog [ci skip] 2018-01-09 16:04:07 -06:00
28fc15028a distinguish between seeds and manual peers in the config/flags
- we only use seeds if we can’t connect to peers in the addrbook.
- we always connect to nodes given in config/flags

Refs #864
2018-01-09 16:03:24 -06:00
179d6062e4 try to connect through addrbook before requesting peers from seeds
we only use seeds if we can’t connect to peers in the addrbook.

Refs #864
2018-01-09 16:03:24 -06:00
c521f385a6 add quick start guide (#1069) 2018-01-09 20:35:47 +00:00
b8214fce66 Merge branch 'develop' into 1087-update-docker 2018-01-09 12:21:23 -06:00
03a14d8342 docs/p2p: updates from review (#1076) 2018-01-09 11:44:49 -06:00
48638eaa20 update docker readme 2018-01-09 11:05:15 -06:00
170777300e update docker
Closes #1087
2018-01-09 11:04:37 -06:00
32311acd01 Vulnerability in light client proxy (#1081)
* Vulnerability in light client proxy

When calling GetCertifiedCommit the light client proxy would call
Certify and even on error return the Commit as if it had been correctly
certified.

Now it returns the error correctly and returns an empty Commit on error.

* Improve names for clarity

The lite package now contains StaticCertifier, DynamicCertifier and
InqueringCertifier. This also changes the method receivers from one
letter to two letter names, which will make future refactoring easier
and follows the coding standards.

* Fix test failures

* Rename files

* remove dead code
2018-01-09 10:36:11 -06:00
b9cbaf8f10 priv-val: fix timestamp for signing things that only differ by timestamp 2018-01-08 16:36:16 -05:00
8d86b6c2d2 Merge pull request #1084 from tendermint/fix-make-dist-script
fix broken `make dist` target
2018-01-08 16:20:36 -05:00
555f560ecd fix broken make dist target 2018-01-08 13:13:47 -06:00
dba4815616 Define requirements of the proposer selection procedure 2018-01-08 14:10:01 +01:00
cf42611187 Merge pull request #997 from tendermint/919-careful-with-validator-voting
check for overflow and underflow while choosing proposer
2018-01-07 16:48:39 -05:00
90c691df2b Merge pull request #1063 from tendermint/feature/Issue1020
NewInquiring returns error instead of swallowing it
2018-01-07 16:30:33 -05:00
13fa23c568 Add error checking 2018-01-06 22:24:58 +01:00
124c58d48f Merge pull request #1071 from tendermint/revert-1053-feature/buildprocess
Revert "Changes to achieve a standardized build process and deterministic builds"
2018-01-05 22:42:19 -08:00
a034600024 Revert "Changes to achieve a standardized build process and deterministic builds" 2018-01-05 22:35:57 -08:00
e0e600df05 Merge branch 'develop' into config 2018-01-06 05:30:38 +00:00
92f5ae5a84 fix vagrant [ci skip] 2018-01-05 22:26:10 -05:00
d57ddec302 Merge pull request #1053 from tendermint/feature/buildprocess
Changes to achieve a standardized build process and deterministic builds
2018-01-05 21:13:42 -05:00
bb3dc10f24 Makefile improvements for deterministic builds based on Bucky's feedback 2018-01-05 14:22:13 -05:00
2cc50938a4 Merge branch 'develop' into feature/buildprocess 2018-01-05 13:01:40 -05:00
ba475d3128 Fix formatting 2018-01-05 13:25:58 +01:00
ed81fb54ec NewInquiring returns error instead of swallowing it 2018-01-05 13:24:16 +01:00
8481da2405 Merge pull request #1046 from tendermint/abci-spec-docs
docs: add abci spec
2018-01-04 13:57:40 -05:00
ecb7303e35 Merge branch 'develop' into abci-spec-docs 2018-01-04 13:57:08 -05:00
9cb45eb7df Add skeleton for functionality and concurrency 2018-01-04 19:08:03 +01:00
6855e62f0a Merge pull request #1052 from tendermint/feature/p2p_docs
docs: P2P Documentation
2018-01-04 12:32:28 -05:00
17b61db40a Document p2p and rpc messages 2018-01-04 18:12:48 +01:00
7b52499463 Start writing mempool specification
Include overview and configuration options.
2018-01-04 17:11:35 +01:00
f67f99c227 Extended install document with docker option. Added extra checks to developer's build target. 2018-01-03 17:24:11 -05:00
0430ebf95c Makefile changes for cross-building and standardized builds using gox 2018-01-03 14:58:23 -05:00
f602de437e Move P2P docs into docs folder 2018-01-03 10:49:47 +01:00
a573b20888 docs: add counter/dummy code snippets
closes https://github.com/tendermint/abci/issues/134
2018-01-03 01:23:38 +00:00
488ae529ad p2p: authenticate peer ID 2018-01-01 23:23:11 -05:00
6e823c6e87 p2p: support addr format ID@IP:PORT 2018-01-01 23:08:20 -05:00
7d35500e6b p2p: add ID to NetAddress and use for AddrBook 2018-01-01 22:39:08 -05:00
a17105fd46 p2p: peer.Key -> peer.ID 2018-01-01 22:39:05 -05:00
b289d2baf4 persistent node key and ID 2018-01-01 21:21:42 -05:00
f2e0abf1dc p2p: reorder some checks in addPeer; add comments to NodeInfo 2018-01-01 21:21:39 -05:00
528154f1a2 p2p: PrivKey need not be Ed25519 2018-01-01 19:44:01 -05:00
bc71840f06 more p2p docs 2018-01-01 16:30:36 -05:00
cd15b677ec docs: add abci spec 2018-01-01 15:35:28 +00:00
1acb12edf5 p2p docs 2017-12-31 17:11:09 -05:00
008de93bbe Merge pull request #1039 from tendermint/add_consensus_spec
Spec of consensus/gossip protocol
2017-12-31 14:59:32 -05:00
4e834baa9a docs: update ecosystem.rst (#1037)
* docs: update ecosystem.rst

* typo [ci skip]
2017-12-31 13:54:50 +00:00
96e0e4ab5a Describe messages sent as part of consensus/gossip protocol 2017-12-30 21:18:12 +01:00
381fe19335 changelog date [ci skip] 2017-12-29 17:51:19 -05:00
ff99ca7cdf bump wal test timeout 2017-12-29 17:51:13 -05:00
60f95cd9ea changelog and version 2017-12-29 11:28:44 -05:00
28bbeac763 state: send byzantine validators in BeginBlock 2017-12-29 11:26:55 -05:00
e97e0bacd1 update glide 2017-12-29 11:11:13 -05:00
abfdfe67e8 test/p2p: add some timeouts 2017-12-29 11:02:47 -05:00
992371b4cf Merge pull request #1035 from tendermint/readme-min-requirements
README: document the minimum Go version
2017-12-29 10:24:57 -05:00
07eeddc5e1 Merge pull request #1015 from tendermint/state_funcs
state: move methods to funcs
2017-12-29 10:24:22 -05:00
3b70c89e07 README: document the minimum Go version
Solidify in writing, the minimum Go version that
we support, as Go1.9.
2017-12-28 23:26:45 -07:00
444db4c242 metalinter 2017-12-28 23:15:54 -05:00
cb845ebff5 fix EvidencePool and VerifyEvidence 2017-12-28 23:15:54 -05:00
6112578d07 ValidateBlock is a method on blockExec 2017-12-28 23:15:54 -05:00
ae68fcb78a move fireEvents to ApplyBlock 2017-12-28 23:15:54 -05:00
8d8d63c94c changelog 2017-12-28 23:15:54 -05:00
1d6f00859d fixes from review 2017-12-28 23:15:54 -05:00
397251b0f4 fix evidence 2017-12-28 23:15:54 -05:00
537b0dfa1a use NopEventBus 2017-12-28 23:15:54 -05:00
0acca7fe69 final updates for state 2017-12-28 23:15:54 -05:00
bac60f2067 blockchain: update for new state 2017-12-28 23:15:54 -05:00
f82b7e2a13 state: re-order funcs. fix tests 2017-12-28 23:15:54 -05:00
9e6d088757 state: BlockExecutor 2017-12-28 23:15:54 -05:00
c915719f85 *State->State; SetBlockAndValidators->NextState 2017-12-28 23:15:54 -05:00
f55135578c state: move methods to funcs 2017-12-28 23:15:54 -05:00
139eca0177 Merge pull request #1027 from tendermint/1026-error-signing-vote-wal-gen
change directory for each call, not only for each test
2017-12-28 16:08:52 -05:00
a8e625e99d config: unexpose chainID 2017-12-28 20:49:02 +00:00
a92a32b862 config: lil fixes 2017-12-28 20:49:02 +00:00
9da5cd0180 rebase fix 2017-12-28 20:49:02 +00:00
a6f2e502e7 move genesis.json file into config dir 2017-12-28 20:49:02 +00:00
69d8c2e554 fixes after my own review 2017-12-28 20:49:02 +00:00
70ba608850 config: write all default options to config file
config: test the default file

docs: spiff up config

config: minor fixes & comments

config: simplify test

config; use a seperate config directory, #556

config: update docs & parameterize file paths

config: PR comments

config: use the default object

fix a rebase error
2017-12-28 20:49:02 +00:00
75182f7205 change directory for each call, not only for each test
Fixes #1026
2017-12-28 11:17:15 -06:00
41caa4415c Merge pull request #1024 from tendermint/1023-tendermint-version
remove quotes from `tendermint version`
2017-12-28 10:14:39 -05:00
c611cc7268 remove quotes from tendermint version
before:
0.14.0-'88f5f21d'

after:
0.14.0-88f5f21d

Fixes #1023
2017-12-28 09:02:25 -06:00
d14ec7d7d2 Merge pull request #1011 from tendermint/1006-panic-on-light-client-startup
protect memStoreProvider#byHash map by mutex
2017-12-27 15:30:59 -05:00
4ca19e33c2 add mutex to memStoreProvider
Fixes #1006

```
goroutine 230 [runnable]:
github.com/cosmos/gaia/vendor/golang.org/x/crypto/ripemd160.(*digest).Sum(0xc420ac2af0, 0x0, 0x0, 0x0, 0xc420c01360, 0xc420c01378, 0x20)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/golang.org/x/crypto/ripemd160/ripemd160.go:119 +0x2c9
github.com/cosmos/gaia/vendor/github.com/tendermint/tmlibs/merkle.KVPair.Hash(0x49447e8, 0x7, 0x47ff760, 0xc420048d50, 0xc420aba9a0, 0x14, 0x20)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tmlibs/merkle/simple_tree.go:122 +0x200
github.com/cosmos/gaia/vendor/github.com/tendermint/tmlibs/merkle.(*KVPair).Hash(0xc4200f7ae0, 0xc420aba9a0, 0x14, 0x20)
	<autogenerated>:1 +0x57
github.com/cosmos/gaia/vendor/github.com/tendermint/tmlibs/merkle.SimpleHashFromHashables(0xc420111900, 0x9, 0x10, 0x10, 0xc420ad06c0, 0xc420087500)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tmlibs/merkle/simple_tree.go:87 +0xaa
github.com/cosmos/gaia/vendor/github.com/tendermint/tmlibs/merkle.SimpleHashFromMap(0xc420b987e0, 0xc420b987e0, 0x4941892, 0x3)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tmlibs/merkle/simple_tree.go:96 +0x4d
github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/types.(*Header).Hash(0xc420a541a0, 0x4034f, 0xc420a28530, 0xa)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/types/block.go:177 +0x54a
github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/lite.Commit.ValidateBasic(0xc420a541a0, 0xc420a1e300, 0xc420a28530, 0xa, 0xb, 0x27)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/lite/commit.go:83 +0x1c9
github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/lite/files.(*provider).StoreCommit(0xc4202f2780, 0xc420a541a0, 0xc420a1e300, 0xc420a24870, 0x0, 0x0)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/lite/files/provider.go:71 +0x5e
github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/lite.cacheProvider.StoreCommit(0xc4202f27a0, 0x2, 0x2, 0xc420a541a0, 0xc420a1e300, 0xc420a24870, 0xc420a541a0, 0xc420a1e300)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/lite/provider.go:39 +0x8f
github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/lite.(*cacheProvider).StoreCommit(0xc4202f27c0, 0xc420a541a0, 0xc420a1e300, 0xc420a24870, 0x2, 0xc420a541a0)
	<autogenerated>:1 +0x70
github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/lite.NewInquiring(0xc420990610, 0xa, 0xc420a541a0, 0xc420a1e300, 0xc420a24870, 0x4f3eb80, 0xc4202f27c0, 0x4f3e5c0, 0xc4202f2840, 0xa)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/lite/inquirer.go:29 +0x5c
github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client.GetCertifier(0xc420990610, 0xa, 0x4f3eb80, 0xc4202f27c0, 0x4f3e5c0, 0xc4202f2840, 0xc4200f68a0, 0xc420b21888, 0x470eece)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client/common.go:47 +0x141
github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client/commands.GetCertifier(0x4f46aa0, 0xc4200f68a0, 0xc420b218e0)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client/commands/common.go:82 +0x83
github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client/commands/query.GetWithProof(0xc420a260c0, 0x22, 0x30, 0x0, 0x4947dd6, 0xc42016a000, 0xc420b219a0, 0x4389d85, 0x0, 0x0, ...)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client/commands/query/get.go:73 +0x52
github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client/commands/query.Get(0xc420a260c0, 0x22, 0x30, 0x0, 0x1, 0x0, 0xc420b21a08, 0x43c9c91, 0xc4200a20f0, 0x4947dd6, ...)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client/commands/query/get.go:64 +0x178
github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client/commands/query.GetParsed(0xc420a260c0, 0x22, 0x30, 0x47d1440, 0xc420b984e0, 0x0, 0x1, 0x30, 0x1d, 0x40)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/client/commands/query/get.go:31 +0x5f
github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/modules/coin/rest.doQueryAccount(0x4f3d300, 0xc4201ee0e0, 0xc420111500)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/modules/coin/rest/handlers.go:66 +0x3a5
net/http.HandlerFunc.ServeHTTP(0x4a9d808, 0x4f3d300, 0xc4201ee0e0, 0xc420111500)
	/usr/local/go/src/net/http/server.go:1918 +0x44
github.com/cosmos/gaia/vendor/github.com/gorilla/mux.(*Router).ServeHTTP(0xc4201aab40, 0x4f3d300, 0xc4201ee0e0, 0xc420111500)
	/Users/mappum/go/src/github.com/cosmos/gaia/vendor/github.com/gorilla/mux/mux.go:150 +0xed
net/http.serverHandler.ServeHTTP(0xc4209992b0, 0x4f3d300, 0xc4201ee0e0, 0xc420111300)
	/usr/local/go/src/net/http/server.go:2619 +0xb4
net/http.(*conn).serve(0xc4200b5540, 0x4f3df80, 0xc420086900)
	/usr/local/go/src/net/http/server.go:1801 +0x71d
created by net/http.(*Server).Serve
	/usr/local/go/src/net/http/server.go:2720 +0x288
```
2017-12-27 15:29:17 -05:00
1a0db878bf Merge pull request #1009 from tendermint/spec
Spec
2017-12-27 15:23:13 -05:00
53eb9aca2b Merge pull request #592 from tendermint/evidence
track evidence, include in block
2017-12-27 15:22:24 -05:00
caccabd4e5 spec: fixes from review 2017-12-27 15:14:49 -05:00
d0e0ac5fac types: better error messages for votes 2017-12-27 14:46:24 -05:00
7d81a3f4a5 address some comments from review 2017-12-27 01:27:03 -05:00
f95b7529eb Merge pull request #999 from tendermint/feature/result-hash-header
Add results hash to header
2017-12-26 20:49:20 -05:00
6a4fd46479 fixes from rebase 2017-12-26 20:42:34 -05:00
b01b1e4758 remove unused var 2017-12-26 20:27:40 -05:00
014b0b9944 evidence: reactor test 2017-12-26 20:27:40 -05:00
5904f6df8b minor fixes from review 2017-12-26 20:27:40 -05:00
0f293bfc2b remove some TODOs 2017-12-26 20:27:40 -05:00
cfbedec719 evidence: reactor test 2017-12-26 20:27:40 -05:00
666ae244b3 evidence: pool test 2017-12-26 20:27:40 -05:00
c13e93d63e evidence: store tests and fixes 2017-12-26 20:27:40 -05:00
c2585b5525 evidence_pool.go -> pool.go. remove old test files 2017-12-26 20:27:40 -05:00
1d021c2790 update consensus/test_data/many_blocks.cswal 2017-12-26 20:27:40 -05:00
cc418e5dab state.VerifyEvidence enforces EvidenceParams.MaxAge 2017-12-26 20:27:32 -05:00
c7acdfadf2 evidence: more funcs in store.go 2017-12-26 20:27:32 -05:00
869d873d5c state.ApplyBlock takes evpool and calls MarkEvidenceAsCommitted 2017-12-26 20:27:32 -05:00
3271634e7a types: evidence cleanup 2017-12-26 20:26:21 -05:00
4854c231e1 evidence store comments and cleanup 2017-12-26 20:26:21 -05:00
7a18fa887d evidence linked with consensus/node. compiles 2017-12-26 20:26:21 -05:00
6c4a0f9363 cleanup evidence pkg. state.VerifyEvidence 2017-12-26 20:26:21 -05:00
f7731d38f6 some comments and cleanup 2017-12-26 20:25:14 -05:00
df3f4de7c3 check evidence is from validator; some cleanup 2017-12-26 20:25:14 -05:00
10c43c9edc introduce evidence store 2017-12-26 20:25:14 -05:00
fe4b53a463 EvidencePool 2017-12-26 20:24:54 -05:00
5b1f987ed1 mempool: remove Peer interface. use p2p.Peer 2017-12-26 20:24:12 -05:00
48d778c4b3 types/params: introduce EvidenceParams 2017-12-26 20:24:12 -05:00
7d086e9524 check if we already have evidence 2017-12-26 20:21:17 -05:00
6e9433c7a8 post rebase fix 2017-12-26 20:21:17 -05:00
39299e5cc1 consensus: note about duplicate evidence 2017-12-26 20:21:17 -05:00
eeab0efa56 types: tx.go comments 2017-12-26 20:21:17 -05:00
77e45756f2 types: Evidences for merkle hashing; Evidence.String() 2017-12-26 20:21:17 -05:00
9cdcffbe4b types: comments; compiles; evidence test 2017-12-26 20:21:17 -05:00
50850cf8a2 verify sigs on both votes; note about indices 2017-12-26 20:21:17 -05:00
35587658cd verify evidence in block 2017-12-26 20:21:17 -05:00
4661c98c17 add pubkey to conflicting vote evidence 2017-12-26 20:21:17 -05:00
7928659f70 track evidence, include in block 2017-12-26 20:21:17 -05:00
f80f6445a6 fix test 2017-12-26 20:15:09 -05:00
336c2f4fe1 rpc: fix getHeight 2017-12-26 20:08:25 -05:00
bfcb40bf6b validate block.ValidatorsHash 2017-12-26 20:00:45 -05:00
051c2701ab remove LastConsensusParams 2017-12-26 19:56:39 -05:00
028ee58580 call it LastResultsHash 2017-12-26 19:53:26 -05:00
801e3dfacf rpc: getHeight helper function 2017-12-26 19:37:42 -05:00
4171bd3bae fixes 2017-12-26 19:24:45 -05:00
73fb1c3a17 consolidate saveResults/SaveABCIResponses 2017-12-26 19:24:45 -05:00
d65234ed51 Add /block_results?height=H as rpc endpoint
Expose it in rpc client
Move ABCIResults into tendermint/types from tendermint/state
2017-12-26 19:24:25 -05:00
58c5df729b Add ResultHash to header 2017-12-26 19:24:25 -05:00
632cc918b4 Save/Load Results for every height
Add some tests.
Behaves like saving validator set, except it always saves at each height
instead of a reference to last changed.
2017-12-26 19:24:25 -05:00
f870a49f42 Add ABCIResults with Hash and Proof to State
State maintains LastResultsHash
Verify that we can produce unique hashes for each result,
and provide valid proofs from the root hash.
2017-12-26 19:24:25 -05:00
d844799b3b Merge branch '950-enforce-less-13-val-changes-per-block' into develop 2017-12-26 19:22:21 -05:00
3ea1145486 bring back test 2017-12-26 19:22:15 -05:00
d4716fc03c state 2017-12-26 18:43:03 -05:00
16227594ef notes about block 1 2017-12-26 16:33:42 -05:00
65cdb07f0c merkle 2017-12-26 15:48:17 -05:00
eb73e82279 encoding.md 2017-12-26 15:30:56 -05:00
d6fbfddddd spec.md -> blockchain.md. some fixes 2017-12-26 15:30:27 -05:00
1339a44402 add safe*Clip funcs 2017-12-26 14:13:12 -06:00
b8215d8ac8 more test cases 2017-12-26 13:30:00 -06:00
289d92c97d consensus: remove log stmt. closes #987 2017-12-26 10:41:31 -05:00
6c39c77fc5 Merge pull request #996 from ricardohsd/types-add-tests-to-vote
Add more tests to types/vote.go
2017-12-26 10:32:07 -05:00
69c3a7640b add safeAdd & safeSub plus quickcheck tests 2017-12-25 18:39:14 -06:00
e8b0458f16 check for overflow and underflow while choosing proposer
Refs #919
2017-12-25 18:39:14 -06:00
6b89639f90 update docs 2 [ci skip] 2017-12-25 17:58:15 -06:00
9b25f7325a update docs [ci skip] 2017-12-25 17:53:54 -06:00
0093f9877a change voting power change, not number of vals 2017-12-25 17:49:36 -06:00
cf0b5d3715 enforce <1/3 validator updates
Refs #950
2017-12-25 12:10:53 -06:00
616f7e74db Merge pull request #1001 from tendermint/makefile
Cleaned up makefile
2017-12-25 12:09:10 -05:00
14c812a39c tmlibs timer fix 2017-12-25 11:11:55 -05:00
1e52751344 update tests for makefile 2017-12-25 10:24:41 -05:00
d7ac6e516a Cleaned up makefile 2017-12-23 02:23:05 -08:00
c2436c46e6 Merge pull request #972 from tendermint/feature/enhance-endblock
Update EndBlock parameters
2017-12-22 01:30:58 -05:00
e3585a6eb0 wip: tendermint specification 2017-12-21 22:36:37 -05:00
38608b1b0f comment and tmlibs fix 2017-12-21 18:32:40 -05:00
2b634dab32 Merge pull request #994 from tendermint/clean/block-validation
Clean/block validation
2017-12-21 17:53:11 -05:00
91acc51cd1 fix test 2017-12-21 17:52:06 -05:00
dc54ba67e4 state: TestValidateBlock 2017-12-21 17:51:03 -05:00
35521b553a save historical consensus params 2017-12-21 17:46:25 -05:00
70a744558c types: params.Update() 2017-12-21 17:00:52 -05:00
4b789ff7e9 another cmn fix 2017-12-21 16:49:47 -05:00
306657a118 no patience for metalinter right now 2017-12-21 16:49:47 -05:00
be765e4cb9 update glide for cmn fixes 2017-12-21 16:49:47 -05:00
b5857da877 forgot file 2017-12-21 16:49:47 -05:00
3ad055ef3a fix randPort 2017-12-21 16:49:47 -05:00
3d00c477fc separate block vs state based validation 2017-12-21 16:49:47 -05:00
c2912d612a update glide 2017-12-21 16:49:47 -05:00
a3c7525249 Merge pull request #993 from tendermint/984-priv-validator-signing
priv validator returns last sign bytes if h/r/s matches
2017-12-21 16:30:22 -05:00
f81025631e update comment [ci skip] 2017-12-21 16:28:05 -05:00
9c03c58de2 priv validator checks if only difference is timestamp; else error 2017-12-21 15:37:27 -05:00
0ffd60b8cf ValidatorSetUpdates -> ValidatorUpdates 2017-12-21 11:52:26 -06:00
d5baa6601c types: Add test for IsVoteTypeValid 2017-12-21 18:13:31 +01:00
19eeef0aad types: Rename exampleVote to examplePrecommit on vote_test
exampleVote doesn't express the type of the vote.
2017-12-21 18:13:31 +01:00
e76392e330 types: Update String() test to assert Prevote type 2017-12-20 23:21:30 +01:00
a1cc9ac642 priv validator returns last sign bytes if h/r/s matches
since now we have time in the msgs and we might crash between writing
the priv val and writing to wal.

Refs #984
2017-12-20 14:41:43 -06:00
67c3af3bf8 cmd/tendermint: fix initialization file creation checks (#991)
* cmd/tendermint: fix initialization file creation checks

Fixes #989.

The original initialization sequence started to inexplicably
fail
```shell
tendermint unsafe_reset_all
tendermint init
tendermint node --proxy_app=dummy
```

used to fail with
```shell
ERROR: Failed to create node: Couldn't read GenesisDoc file: open
/Users/emmanuelodeke/.tendermint/genesis.json: no such file or directory
```

because the initialization sequence always assumed that the
genesisDoc would only be set if the privValidator was generated.

However, `tendermint unsafe_reset_all` only created the
`priv_validator.json` file which would mean that then running
`tendermint init` would never create the `genesis.json` file
which if following the recommended sequence would then fail
since the `genesis.json` was absent.

* cmd/tendermint: Load PrivValidatorFS if existent, lest generate it

Feedback from @melekes

* change logging messages for init cmd

Refs #989
2017-12-20 12:50:27 -06:00
843e1ed400 Updates -> ValidatoSetUpdates 2017-12-19 13:03:39 -06:00
4bca6bf6f5 fix test 2017-12-19 12:30:34 -05:00
960b25408f Store LastConsensusHash in State as well
Update all BlockValidation that it matches the last state
2017-12-19 12:28:08 -05:00
45bc106de7 Updated lite tests to set ConsensusHash in header 2017-12-19 12:28:08 -05:00
d151e36ea8 Add ConsensusHash to header 2017-12-19 12:28:08 -05:00
56cada6a0c Validate ConsensusParams returned from abci app 2017-12-19 12:28:08 -05:00
a0b2d77bef Add hash to ConsensusParams 2017-12-19 12:28:08 -05:00
030fd00232 Added tests for applying consensus param changes 2017-12-19 12:28:08 -05:00
d21f39160f Apply ConsensusParamChanges to state/State 2017-12-19 12:28:08 -05:00
4265a94bfe Update EndBlock parameters
* Update abci dependencies
* Modify references from Diffs to Changes
* Fixes issues #924
2017-12-19 12:28:08 -05:00
652d1e3de8 Merge pull request #979 from tendermint/934-node-fails-to-parse-seeds
strip protocol if defined
2017-12-19 12:26:32 -05:00
b33cff4cb7 Merge pull request #981 from tendermint/977-wal-generator
enable logging for wal_generator and set timeout to 1 min
2017-12-19 12:25:58 -05:00
e0fe84a856 Merge branch 'develop' into 977-wal-generator 2017-12-19 11:11:26 -05:00
783ffdb7fd Merge pull request #983 from tendermint/circle-testing
Circle testing
2017-12-19 11:09:22 -05:00
cb3ac6987e remove some debugs 2017-12-19 10:11:37 -05:00
5a83e58428 stop eventBus 2017-12-17 20:16:02 -06:00
3f02ab0ead unidirectional channel 2017-12-16 22:20:07 -06:00
99c58fc561 enable logging for wal_generator and set timeout to 1 min
Refs #977
2017-12-16 21:59:10 -06:00
a86df17ceb crank city 2017-12-16 19:55:04 -05:00
5d04ccbe51 excessive logging. update tmlibs for timer fix 2017-12-16 19:16:08 -05:00
61dc357bb3 test/p2p/kill_all: longer timeout 2017-12-16 13:36:52 -05:00
d7cb2f850d more logs in p2p 2017-12-16 13:36:52 -05:00
bfe0a4a8ac more logging 2017-12-16 13:36:52 -05:00
0ec7909ec3 more logging in p2p and consensus 2017-12-16 13:36:52 -05:00
b5b912e2c4 Merge remote-tracking branch 'origin/977-wal-generator' into develop 2017-12-16 13:36:32 -05:00
9504a593e9 Merge pull request #980 from tendermint/fix-test-in-develop
add missing Timestamp to Votes
2017-12-15 22:11:47 -05:00
f8f28c8942 enable logging for wal_generator and set timeout to 1 min
Refs #977
2017-12-15 16:15:09 -06:00
8fc7d63cf8 add missing Timestamp to Votes
Fixes:

```
panic: Panicked on a Sanity Check: can't encode times below 1970 [recovered]
        panic: Panicked on a Sanity Check: can't encode times below 1970

goroutine 2042 [running]:
testing.tRunner.func1(0xc420e8c0f0)
        /usr/local/go/src/testing/testing.go:711 +0x5d9
panic(0xcd9e20, 0xc420c8c270)
        /usr/local/go/src/runtime/panic.go:491 +0x2a2
github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.PanicSanity(0xcd9e20, 0xf8ddd0)
        /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/errors.go:26 +0x120
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.WriteTime(0x0, 0x0, 0x0, 0x1306440, 0xc4201607e0, 0xc420e31658, 0xc420e31680)
        /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/time.go:19 +0x11e
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.writeReflectBinary(0xdc9e40, 0xc4201fcf30, 0x199, 0x1317b80, 0xdc9e40, 0xc98451, 0x9, 0x0, 0xdc9e40, 0xc420ead9c0, ...)
        /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/reflect.go:525 +0x22f0
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.writeReflectBinary(0xd25400, 0xc42000e2e8, 0x196, 0x1317b80, 0xd92d60, 0xc9a195, 0xa, 0x0, 0xcc8ce0, 0xc420164920, ...)
        /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/reflect.go:530 +0x21e7
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.writeReflectBinary(0xcc8ce0, 0xc4209f95b8, 0x197, 0x1317b80, 0xcc8ce0, 0xc9a195, 0xa, 0x0, 0xcc8ce0, 0xc420164920, ...)
        /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/reflect.go:518 +0x2509
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.writeReflectBinary(0xd873e0, 0xc4209f9580, 0x16, 0x1317b80, 0xd79400, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/reflect.go:530 +0x21e7
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.WriteBinary(0xd873e0, 0xc4209f9580, 0x1306440, 0xc4201607e0, 0xc420e31658, 0xc420e31680)
        /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/wire.go:80 +0x15f
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.BinaryBytes(0xd873e0, 0xc4209f9580, 0x3, 0x8, 0xc420160798)
        /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/util.go:15 +0xb8
github.com/tendermint/tendermint/blockchain.(*BlockStore).SaveBlock(0xc4201342a0, 0xc420eac180, 0xc420130640, 0xc4209f9580)
        github.com/tendermint/tendermint/blockchain/_test/_obj_test/store.go:192 +0x439
github.com/tendermint/tendermint/blockchain.TestBlockStoreSaveLoadBlock(0xc420e8c0f0)
        /go/src/github.com/tendermint/tendermint/blockchain/store_test.go:128 +0x609
testing.tRunner(0xc420e8c0f0, 0xf20830)
        /usr/local/go/src/testing/testing.go:746 +0x16d
created by testing.(*T).Run
        /usr/local/go/src/testing/testing.go:789 +0x569
exit status 2
FAIL
```
2017-12-15 13:59:25 -06:00
c513649df4 strip protocol if defined
Fixes #934
2017-12-15 13:36:08 -06:00
a6911825b0 PanicCrisis is deprecated 2017-12-15 13:35:49 -06:00
eddabab5e4 Merge pull request #965 from tendermint/573-handle-corrupt-wal-file
Handle corrupt WAL file
2017-12-15 14:33:16 -05:00
3eee69de2d Merge pull request #954 from tendermint/668-send-absent-validators
Send absent validators
2017-12-15 13:55:52 -05:00
068d83bce8 Merge pull request #677 from tendermint/blockchain-test-store
blockchain: add tests for BlockStore
2017-12-15 13:33:55 -05:00
7f649ccf23 fixes from Frey's review 2017-12-15 12:21:15 -06:00
808b830942 add a unit test
Refs #668
2017-12-15 12:13:02 -06:00
d669816a1b send absent validators in BeginBlock
Refs #668
2017-12-15 12:13:02 -06:00
e40689b9cc PanicCrisis is deprecated 2017-12-15 11:59:45 -06:00
709cf18aef add gofuzz test for consensus wal 2017-12-15 11:56:24 -06:00
e57cad6c3f correct maxMsgSizeBytes 2017-12-15 11:42:53 -06:00
4f94caa1b9 explain what to do in case of truncation [ci skip] 2017-12-15 11:11:21 -06:00
78a682e4b6 blockchain: test fixes 2017-12-15 12:07:48 -05:00
21d030dbfb Merge pull request #975 from tendermint/974-fix-test-in-develop
add missing Timestamp to Vote
2017-12-14 09:22:11 -05:00
72da553ed9 add missing Timestamp to Vote
Fixes #974
2017-12-13 22:24:06 -06:00
b78606d94f Merge pull request #967 from tendermint/feature/total-tx
Add TotalTx to block header
2017-12-13 17:09:48 -06:00
a6f719a402 Add tests for block validation 2017-12-13 19:54:16 +01:00
e0fbd148ef Merge pull request #958 from tendermint/pex-on-by-default
activate PEX reactor by default
2017-12-13 12:52:17 -06:00
2f91289880 update changelog [ci skip] 2017-12-13 12:26:12 -06:00
462b755a60 activate PEX reactor by default 2017-12-13 12:25:48 -06:00
0a2ecaa393 Merge pull request #953 from tendermint/feature/time-fields
Add Timestamp to Proposal/Vote
2017-12-13 12:18:55 -06:00
dedf03bb81 Add TotalTx to block header, issue #952
Update state to keep track of this info.
Change function args as needed.
Make NumTx also an int64 for consistency.
2017-12-13 12:20:53 +01:00
64f056b57d Merge branch '916-remove-sleeps-from-tests' into develop 2017-12-12 16:43:36 -05:00
90df9fa1bf p2p/trust: remove extra channels 2017-12-12 16:43:19 -05:00
eae6e6381e trust metric is now a service and the test ticker has been added 2017-12-12 15:33:42 -05:00
04a18e0a97 briefly describe the recover process [ci skip] 2017-12-12 13:03:09 -06:00
06aece31cf lower the max message size 2017-12-12 13:02:40 -06:00
e0296d6c3c consensus: fix makeBlockchainFromWAL 2017-12-12 12:14:15 -05:00
5ffb5f01cc Add more tests for Proposal/Vote serialization
String() and Proposal valid after serializing.
To be safe, but mainly to increase test coverage for the PR
2017-12-12 12:59:51 +01:00
8576ad58bd Cleanup canonical json 2017-12-12 12:59:51 +01:00
c4860f6c29 Force CanonicalTime to UTC
fixes issue with vote serialization breaking the signatures
2017-12-12 12:59:51 +01:00
850310b034 Add test to isolate precommit failure
types/vote_test.go now checks signature on a serialized and
then deserialized vote. Turns out go-wire time encoding doesn't
respect timezones, and the signatures don't check out.
2017-12-12 12:59:51 +01:00
a29c781295 Add default timestamp to all instances of *types.Vote 2017-12-12 12:59:51 +01:00
599673690c Add timestamp to vote canonical encoding 2017-12-12 12:59:51 +01:00
7deda53b7c Add Timestamp to Proposal for issue #929
Store it as time.Timestamp locally, encode it as RFC3339 with milliseconds
before signing the canonical form.
2017-12-12 12:59:51 +01:00
5ecae52bf1 Merge branch 'master' into develop 2017-12-12 02:31:47 -05:00
ac2d0edb2f Merge pull request #964 from tendermint/fix-gometa-makefile
fix gometalinter.v2 automatically
2017-12-12 02:26:18 -05:00
ae632654d2 add tools check with short circuit 2017-12-11 23:00:18 -08:00
88f5f21dbb Merge pull request #960 from tendermint/release-v0.14.0
Release v0.14.0
2017-12-12 01:28:35 -05:00
49e5510953 remove tools from all 2017-12-11 21:44:53 -08:00
a6644f7477 remove gopath prefixes
it's safe because I added GOPATH to PATH earlier today
2017-12-11 23:05:22 -06:00
10265d8667 add tools to make all because it's required for test target 2017-12-11 23:02:42 -06:00
8be708fe5b fix spelling and makefile gometalinter.v2 2017-12-11 20:48:15 -08:00
5facfafbd5 Merge branch 'develop' into release-v0.14.0 2017-12-11 23:09:04 -05:00
11761d1769 initial port of cosmos-sdk basecli proxy 2017-12-11 22:23:13 -05:00
2c14488b93 Merge pull request #963 from tendermint/remove-get-deps-from-makefile
Remove get_deps, update_deps and list_deps from Makefile
2017-12-11 21:56:05 -05:00
c127bce73b Merge pull request #962 from tendermint/wait-a-little-longet-on-ci
wait 5 sec for a block on CircleCI
2017-12-11 21:54:57 -05:00
af79a2a59e fix error msg 2017-12-11 19:50:05 -06:00
ee66476d62 set max msg size
otherwise, it is easy to get OutOfMemory panic (somebody can even expoit
this)
2017-12-11 19:48:57 -06:00
40f9261d48 handle data corruption errors
Refs #573
2017-12-11 19:48:20 -06:00
69205594cc add gopath to path on CircleCI 2017-12-11 16:59:08 -06:00
d943f66abc remove get_deps, update_deps and list_deps
Rationale: they only lead to broken builds and should not be used by
anyone.
2017-12-11 16:55:40 -06:00
b2385b46cf wait 5 sec for a block on CircleCI
Fixes:
```
--- FAIL: TestHandshakeReplaySome (12.40s)
        replay_test.go:332: waited too long for tendermint to produce 6 blocks
```
2017-12-11 16:22:27 -06:00
2af32d6665 changelog and version bump 2017-12-11 15:05:56 -05:00
5c58db3bb4 changelog [ci skip] 2017-12-11 14:49:34 -05:00
24a9491203 Merge pull request #955 from tendermint/939-p2p-exponential-backoff-on-reconnect
p2p: exponential backoff on reconnect. closes #939
2017-12-11 14:25:39 -05:00
5511bd8e85 p2p: exponential backoff on reconnect. closes #939 2017-12-11 13:41:09 -05:00
f1ca2b3a3a Merge pull request #698 from tendermint/feat-appveyor
WIP: Run tests on AppVeyor
2017-12-10 20:06:34 -05:00
10fcefe346 appveyor: use make 2017-12-10 20:07:44 -05:00
0bfc11f1ba blockchain: note about store tests needing simplification ... 2017-12-10 20:03:58 -05:00
96998a5498 blockchain: Block creator helper for compressing tests as per @ebuchman 2017-12-10 19:58:22 -05:00
2da5299924 blockchain: less fragile and involved tests for blockstore
With feedback from @ebuchman, to make the tests nicer
and less fragile.
2017-12-10 19:58:22 -05:00
83b40b25d6 blockchain: deduplicate store header value tests 2017-12-10 19:57:06 -05:00
05f30b3e28 blockchain: updated store docs/comments from review 2017-12-10 19:57:06 -05:00
116a61beb1 blockchain: update store comments 2017-12-10 19:57:06 -05:00
8c86bb8024 blockchain: add tests and more docs for BlockStore
Add tests to test store, to the fullest reasonable extent for
paths that can taken by input arguments altering internal behavior,
as well as by mutating content in the DB.
2017-12-10 19:54:34 -05:00
41bb2c2663 Merge pull request #931 from tendermint/785-wal-improvements
[consensus] remove WAL separator
2017-12-10 19:46:02 -05:00
e7b9cd8ee8 Merge branch 'develop' into 785-wal-improvements 2017-12-10 19:45:52 -05:00
3019b9f320 Merge pull request #948 from tendermint/945-transparent-websocket
bring back transparent websocket (Refs #945)
2017-12-10 19:05:32 -05:00
60872d7d7c Merge pull request #949 from tendermint/docs/trust-metric-usage
Docs/trust metric usage
2017-12-10 19:01:16 -05:00
a37c1143ca adr: update 007 trust metric usage 2017-12-10 19:00:44 -05:00
4e08ee1833 made clarifications based on odeke-em's PR comments 2017-12-10 15:39:43 -05:00
7563870d11 added the trust metric usage guide 2017-12-10 15:39:43 -05:00
12c5a57415 determinisitic linter (#902)
* linter: address gosimple lints

* linter: make deterministic & a rebase fix

* lint/rpc: fix a gosimple lint

* run linter in CI

* fix rebase mistake

* fix makefile

* ugh

* revert Makefile

* add metalinter to CI

* try this

* linter: last little fix

* need glide

* better

* okayy circle, have it your way

* lints: gosimple

* pr comments
2017-12-10 17:44:22 +00:00
101680d603 update changelog [ci skip] 2017-12-10 11:35:22 -06:00
d819d5d324 update changelog [ci skip] 2017-12-10 11:34:08 -06:00
90cdffa067 fixes after my own review (Refs #945) 2017-12-10 11:29:36 -06:00
080640a171 Merge pull request #936 from tendermint/update-dockerfile-to-0.12.1
Update dockerfile to 0.12.1
2017-12-10 12:15:09 -05:00
950a64f756 bring back transparent websocket (Refs #945) 2017-12-10 01:18:10 -06:00
b50cef742d Merge pull request #943 from tendermint/feature/update-vagrantfile
Update Vagrantfile to xenial (16.04 LTS)
2017-12-09 17:03:44 -06:00
4f50935aa2 Merge pull request #946 from ricardohsd/fix-typo
consensus: Fix typo on ticker.go documentation
2017-12-09 17:03:12 -06:00
44f62e5e27 built the WaitForStop functionality into the Stop method 2017-12-09 13:25:28 -05:00
59e89e7664 consensus: Fix typo on ticker.go documentation 2017-12-09 13:14:53 +01:00
5d464364a8 fixed the racy test and removed all the calls to Sleep 2017-12-08 15:51:18 -05:00
2112299586 Cleanup apt-get ala PR comments 2017-12-08 19:20:53 +01:00
c771964a40 Add vagrant_test to Makefile for integration tests 2017-12-08 18:36:58 +01:00
a199ec2813 update docker readme 2017-12-08 11:35:35 -06:00
a28b3fff49 update Dockerfile to 0.13.0 2017-12-08 11:34:34 -06:00
5bcd95f01f Use apt-get/ppa instead of tarballs for golang/docker
Minor cleanup and comments
2017-12-08 18:10:39 +01:00
c84494b36b Update Vagrantfile to xenial (16.04 LTS)
Note default username changed from vagrant to ubuntu in the base image.
2017-12-08 18:10:39 +01:00
7e3a5b7ce8 Merge pull request #942 from tendermint/bugfix/install-stdlib
From CGO_ENABLED=0 from make install
2017-12-08 11:03:05 -06:00
fbfd11de2c add @melekes as codeowner 2017-12-08 11:48:05 -05:00
9657d183f8 Remove CGO_ENABLED=0 from make install
It was writing to stdlib packages net, x/crypto, etc. and failing when it didn't have write access to them (which it often shouldn't)

Fixes issue #941

Explained in golang issue: golang/go#18981 (fixed in develop/1.10)
2017-12-08 17:03:09 +01:00
b98098b1f0 Merge pull request #932 from tendermint/920-default-moniker-to-host-name
default moniker to the host name
2017-12-07 18:34:38 -05:00
1ae14e5a3d Merge pull request #933 from tendermint/880-node-fails-if-one-of-the-seeds-cannot-be-resolved
tolerate unresolvable seeds
2017-12-07 18:27:58 -05:00
7a92a3b729 update docker readme 2017-12-07 13:49:29 -06:00
457c688346 update Dockerfile to point to 0.12.1 2017-12-07 13:48:31 -06:00
c609b18698 tolerate unresolvable seeds (Refs #880) 2017-12-07 13:17:09 -06:00
5ff0bb2100 default moniker to the host name (Refs #920) 2017-12-07 12:49:29 -06:00
90944bb1a2 be specific about what type we're encoding
to be consistent with Decode, which returns TimedWALMessage
2017-12-07 11:45:50 -06:00
07571741c5 [consensus] remove WAL separator (Refs #785)
We don't really need a separator unless we have complex structures
(rows, cells like RDBMS have https://www.sqlite.org/fileformat.html).
2017-12-07 11:36:46 -06:00
14ccc8bc4c Merge pull request #930 from tendermint/468-make-consensus-data-deterministic
make consensus/test_data deterministic
2017-12-06 22:28:03 -05:00
5cb936fa00 fixes after my own review 2017-12-06 18:28:14 -06:00
c6f025f40e generate WAL on the fly (Refs #468) 2017-12-06 16:01:08 -06:00
a2b92c0745 Merge pull request #927 from tendermint/release-v0.13.0
Release v0.13.0
2017-12-06 03:57:49 -05:00
6884463ba2 update changelog [ci skip] 2017-12-06 03:38:03 -05:00
167d0e82f9 fixes and version bump 2017-12-06 03:33:03 -05:00
42e77de6a3 changelog; minor stuff; update glide 2017-12-06 02:45:38 -05:00
58b4a8395b Merge pull request #917 from tendermint/trust-metric-cleanup
Trust metric cleanup
2017-12-06 02:11:38 -05:00
d0dc04001e rpc: make time human readable. closes #926 2017-12-06 01:25:11 -05:00
e101aa9fc8 fix for legacy gowire 2017-12-06 01:21:14 -05:00
6a7c399c2d Merge pull request #923 from tendermint/enable-homebrew-installation-from-source
Enable homebrew installation from source
2017-12-05 00:50:52 -05:00
b3e1341e44 use get rev-parse --short HEAD everywhere instead of GitCommit[:8] 2017-12-04 22:16:19 -06:00
ebdc7ddf20 add missing get_vendor_deps to "make all" 2017-12-04 19:04:15 -06:00
f30ce8b210 remove GitDescribe - no such variable defined in version package
- add "-w -s" flags to reduce binary size (they remove debug info)
2017-12-04 18:19:11 -06:00
76cccfaabd get_vendor_deps does not require all the tools
- remove revision cmd
- rename ensure_tools to tools
2017-12-04 18:19:11 -06:00
440d76647d rename release to test_release 2017-12-04 17:37:32 -06:00
2cc2fade06 remove -extldflags "-static"
golang builds static libraries by default.
2017-12-04 17:35:42 -06:00
e50173c7dc merge 2 rules in .editorconfig 2017-12-04 15:01:28 -06:00
3318cf9aec do not suppose that GOPATH is added to PATH
```
brew install tendermint --HEAD
==> Installing tendermint from tendermint/tendermint
==> Cloning https://github.com/tendermint/tendermint.git
Cloning into '/Users/antonk/Library/Caches/Homebrew/tendermint--git'...
remote: Counting objects: 437, done.
remote: Compressing objects: 100% (412/412), done.
remote: Total 437 (delta 7), reused 129 (delta 2), pack-reused 0
Receiving objects: 100% (437/437), 3.04 MiB | 1006.00 KiB/s, done.
Resolving deltas: 100% (7/7), done.
==> Checking out branch develop
==> make get_vendor_deps
Last 15 lines from /Users/antonk/Library/Logs/Homebrew/tendermint/01.make:
2017-12-04 14:54:54 -0600

make
get_vendor_deps

go get github.com/mitchellh/gox github.com/tcnksm/ghr github.com/Masterminds/glide github.com/alecthomas/gometalinter
make: gometalinter: No such file or directory
make: *** [ensure_tools] Error 1

If reporting this issue please do so at (not Homebrew/brew or Homebrew/core):
https://github.com/tendermint/homebrew-tendermint/issues
```
2017-12-04 15:00:16 -06:00
b37230f6db Merge pull request #918 from tendermint/abci-update
Abci update
2017-12-03 01:36:59 -05:00
1bf57a90df glide: update grpc version 2017-12-02 23:41:12 -05:00
d2db202a2d mempool: assert -> require in test 2017-12-02 23:41:09 -05:00
08857606dc test: fix test/app/counter_test.sh 2017-12-02 23:39:19 -05:00
72e389041c Merge pull request #914 from tendermint/11-response-info-with-invalid-height-crashes-tm
int64 height (Refs #911)
2017-12-02 23:17:41 -05:00
d41c0b10c8 change delta's type from int to int64 2017-12-02 11:48:24 -06:00
898ae53672 types: fix for broken customtype int in gogo 2017-12-02 12:00:46 -05:00
9e20cfee0e glide 2017-12-02 01:56:40 -05:00
9af8da7aad update for new abci int types 2017-12-02 01:47:55 -05:00
c9be2b89f9 mempool: return error on cached txs 2017-12-02 01:15:11 -05:00
388f66c9b3 types: drop uint64 from protobuf.go 2017-12-02 01:07:17 -05:00
cd5a5d332f remove comments for uint64 related to possible underflow [ci skip] 2017-12-01 23:30:08 -06:00
cb9a1dbb4f p2p/trust: lock on Copy() 2017-12-01 23:35:17 -05:00
814541f6d9 p2p/trust: split into multiple files and improve function order 2017-12-01 23:35:12 -05:00
89cbcceac4 error if app returned negative last block height (Fixes #911) 2017-12-01 21:56:08 -06:00
10f7858453 use rand.Int63n, remove underflow check, remove unnecessary cast 2017-12-01 19:22:18 -06:00
922af7c405 int64 height
uint64 is considered dangerous. the details will follow in a blog post.
2017-12-01 19:04:53 -06:00
e9f8e56895 fixes from rebase 2017-12-01 17:25:44 -05:00
3eb069a50c no need in this hack since we have replay now 2017-12-01 17:17:22 -05:00
f1fbf995f7 protect ourselves again underflow (Refs #911) 2017-12-01 17:17:22 -05:00
86af889dfb remove unnecessary casts (Refs #911) 2017-12-01 17:17:22 -05:00
b3492356e6 uint64 height (Refs #911) 2017-12-01 17:17:22 -05:00
b2489b4318 Merge pull request #912 from bluecollarcoding/fix/docs
docs:clarify py-abci/py-tendermint
2017-12-01 02:57:32 -05:00
a5a7e7ac56 Merge pull request #913 from bluecollarcoding/zramsay-patch-1
codecov: ignore docs files
2017-12-01 02:56:34 -05:00
74cbfc68a1 Merge pull request #835 from tendermint/feature/indexing
Indexing DeliverTx tags
2017-12-01 02:54:30 -05:00
6423306980 TestIndexAllTags (unit) 2017-11-30 23:02:40 -06:00
c5b62ce1ee correct abci version 2017-11-30 20:20:35 -06:00
e538e0e077 config variable to index all tags 2017-11-30 20:02:39 -06:00
9314e451c8 Update .codecov.yml 2017-11-30 19:01:50 +00:00
3b61e2854a docs: correction, closes #910 2017-11-30 18:27:46 +00:00
03222d834b update abci dependency 2017-11-30 11:46:28 -06:00
cb9743e567 dummy app now returns one DeliverTx tag 2017-11-29 20:30:37 -06:00
66ad366a4f test searching for tx with multiple same tags 2017-11-29 20:04:26 -06:00
864ad8546e more test cases 2017-11-29 20:04:00 -06:00
58789c52cd add example for tx_search endpoint 2017-11-29 15:30:12 -06:00
a762253e24 do not use AddBatch, prefer copying for now 2017-11-29 15:25:12 -06:00
10d893ee9b update deps 2017-11-29 15:19:45 -06:00
acbc0717d4 add client methods 2017-11-29 15:19:44 -06:00
1e19860585 fixes from my own review 2017-11-29 14:24:18 -06:00
09941b9aa9 fix metalinter warnings 2017-11-29 14:24:18 -06:00
2a5e8c4a47 add minimal documentation for tx_search RPC method [ci skip] 2017-11-29 14:24:18 -06:00
686e0eea9f extract indexing goroutine to a separate indexer service 2017-11-29 14:24:18 -06:00
91f2184003 fixes after bucky's review 2017-11-29 14:24:18 -06:00
3e577ccf4f add tx_search RPC endpoint 2017-11-29 14:24:18 -06:00
ea0b205455 searching transaction results 2017-11-29 14:24:18 -06:00
16cf7a5e0a use a switch when validating tags 2017-11-29 14:23:44 -06:00
56abea7427 rename tm.events.type to just tm.event 2017-11-29 14:23:44 -06:00
461a143a2b remove tx.hash tag from config because it's mandatory 2017-11-29 14:23:44 -06:00
f65e357d2b adapt Tendermint to new abci.Client interface
which was introduced in https://github.com/tendermint/abci/pull/130
2017-11-29 14:23:44 -06:00
4a31532897 remove unreachable code 2017-11-29 14:23:44 -06:00
29cd1a1b8f rewrite indexer to be a listener of eventBus 2017-11-29 14:23:44 -06:00
cd4be1f308 add tx_index config 2017-11-29 14:23:43 -06:00
acae38ab9e validate tags 2017-11-29 14:23:43 -06:00
a52cdbfe43 extract tags from DeliverTx/Result
and send them along with predefined
2017-11-29 14:23:43 -06:00
f233cde9a9 Merge pull request #807 from tendermint/45-change-common-start-signature
service#Start, service#Stop signatures were changed
2017-11-29 20:23:07 +00:00
ceb8ba2e15 comment out gas linter for now 2017-11-29 13:18:34 -06:00
aab54011b3 docs/install: add note about putting GOPATH/bin on PATH 2017-11-29 18:05:51 +00:00
691e266bef ignore ErrAlreadyStarted when starting addrbook in PEXReactor 2017-11-29 10:53:30 -06:00
c6b2334fa3 check for error when stopping WSClient 2017-11-29 10:38:58 -06:00
69b5da766c service#Start, service#Stop signatures were changed
See https://github.com/tendermint/tmlibs/issues/45
2017-11-29 10:38:58 -06:00
a393cf4109 Merge pull request #904 from tendermint/fix-atomic-broadcast-test
test/p2p/atomic_broadcast: wait for node heights before checking app hash
2017-11-28 08:21:15 +00:00
1b120466ee Merge pull request #892 from tendermint/mempool-Stop-method
mempool: implement Mempool.CloseWAL
2017-11-28 06:58:01 +00:00
c8c533cc23 test/p2p/atomic_broadcast: wait for node heights before checking app hash 2017-11-28 05:51:32 +00:00
1e8deacf2e Merge branch 'master' into develop 2017-11-28 04:39:41 +00:00
3595b5931a mempool: implement Mempool.CloseWAL
Fixes https://github.com/tendermint/tendermint/issues/890

Add a CloseWAL method to Mempool to close the underlying WAL file
and then discard it so that further writes to it will have no effect.
2017-11-27 21:37:25 -07:00
c7f923c5b0 Merge pull request #903 from tendermint/hotfix-v0.12.1
Upgrade tmlibs dependency to build on Windows
2017-11-28 04:36:52 +00:00
25f9eb782b Upgrade tmlibs dependency to build on Windows 2017-11-28 04:04:58 +00:00
2009c3d4f1 Merge pull request #884 from tendermint/wal-benchmark-decode
consensus/WAL: benchmark WALDecode across data sizes
2017-11-28 03:39:55 +00:00
c3632bc54a Merge pull request #703 from tendermint/fix-linting
add metalinter to CI and include fixes
2017-11-28 00:02:52 +00:00
d9c87a21a6 run metalinter in make test and run_test.sh 2017-11-27 22:39:12 +00:00
2e76b23c9a rpc: fix tests 2017-11-27 22:39:12 +00:00
9529f12c28 more linting 2017-11-27 22:39:12 +00:00
55b81cc1a1 address linting FIXMEs 2017-11-27 22:39:12 +00:00
c4caad7720 lint madness 2017-11-27 22:39:12 +00:00
2563b4fc92 lint fixes 2017-11-27 22:39:12 +00:00
6f3c05545d fix new linting errors 2017-11-27 22:39:12 +00:00
414a8cb0ba pass tests! 2017-11-27 22:39:12 +00:00
c84c7250ba linting: few more fixes 2017-11-27 22:39:12 +00:00
c7b6faf96a bad goimports 2017-11-27 22:39:12 +00:00
fe37afc0d7 do i need this? 2017-11-27 22:39:12 +00:00
478a10aa41 Write doesn't need error checked 2017-11-27 22:39:12 +00:00
d033470817 lil fixes 2017-11-27 22:39:12 +00:00
7ad8a8ab55 Tests almost passing 2017-11-27 22:39:12 +00:00
a15c7f221d linting: moar fixes 2017-11-27 22:39:11 +00:00
d7cb291fb2 errcheck; sort some stuff out 2017-11-27 22:39:11 +00:00
563faa98de address comments, pr #643 2017-11-27 22:39:11 +00:00
9c62ed4595 run linting first for tests 2017-11-27 22:39:11 +00:00
fe694e1fe1 ... 2017-11-27 22:39:11 +00:00
bc2aa79f9a linter: sort through each kind and address small fixes 2017-11-27 22:39:11 +00:00
48aca642e3 linter: address deadcode, implement incremental lint testing 2017-11-27 22:39:11 +00:00
15651a931e linting errors: tackle p2p package 2017-11-27 22:39:11 +00:00
68e7983c70 linting errors: afew more 2017-11-27 22:39:11 +00:00
8f0237610e linting errors: clean it all up 2017-11-27 22:39:11 +00:00
b75d4f73e7 errcheck: PR comment fixes 2017-11-27 22:39:11 +00:00
b3c5933a23 state: return to-be-used function 2017-11-27 22:39:11 +00:00
331857c9e6 linting: apply errcheck part2 2017-11-27 22:39:11 +00:00
57ea4987f7 linting: apply errcheck part1 2017-11-27 22:39:11 +00:00
d95ba866b8 lint: apply deadcode/unused 2017-11-27 22:39:11 +00:00
1721543e5c linting: apply misspell 2017-11-27 22:39:11 +00:00
46ccbcbff6 linting: apply 'gofmt -s -w' throughout 2017-11-27 22:39:11 +00:00
fc33576bac linting: replace megacheck with metalinter 2017-11-27 22:39:11 +00:00
366bc00b70 Merge pull request #895 from tendermint/894-vagrant-instructions
add Vagrant instructions to CONTRIBUTING guides (Refs #894) [ci skip]
2017-11-27 20:54:32 +00:00
d5cd3a111f Merge pull request #899 from tendermint/feature/lite-client
Rename certifier to lite (#784) and add godocs
2017-11-27 17:21:15 +00:00
94e400a5d6 Merge pull request #896 from tendermint/normalize-priority-and-id
normalize priority and id and remove pointers in ChannelDescriptor
2017-11-27 17:05:38 +00:00
7dd249f754 Merge pull request #882 from caffix/develop
fixed race condition reported in issue #881
2017-11-27 16:50:57 +00:00
12ae1bb5e5 Address comments 2017-11-27 16:23:56 +01:00
248f176c1f Rename light to lite 2017-11-27 16:19:00 +01:00
1871a7c3d0 Rename certifier to light (#784) and add godocs
The certifier package is renamed to light. This is more descriptive
especially in the wider blockchain context. Moreover we are building
light-clients using the light package.

This also adds godocs to all exported functions.

Furthermore it introduces some extra error handling. I've added one TODO
where I would like someone else's opinion on how to handle the error.
2017-11-27 16:18:27 +01:00
59b3dcb5cf normalize priority and id and remove pointers in ChannelDescriptor 2017-11-25 22:01:23 -08:00
fb87590c82 add Vagrant instructions to CONTRIBUTING guides (Refs #894) [ci skip] 2017-11-24 16:42:46 -06:00
38c4de3fc7 Merge pull request #891 from tendermint/fix-vagrantfile
go requires Git (Fixes #879)
2017-11-24 22:07:29 +00:00
ae67408d13 go requires Git (Fixes #879) 2017-11-23 16:55:57 -06:00
42da8cd297 consensus/WAL: benchmark WALDecode across data sizes 2017-11-23 12:43:11 -07:00
887cb6d0cd added public methods to handle locking within the trust metric 2017-11-22 23:42:38 -05:00
aeaf2d0b20 Merge branch 'develop' of https://github.com/tendermint/tendermint into develop 2017-11-22 23:11:01 -05:00
932e472986 Merge pull request #885 from AFDudley/patch-1
Update getting-started.rst to fix broken link
2017-11-22 20:29:30 +00:00
e845987503 p2p: disable trustmetric test while being fixed 2017-11-22 20:20:53 +00:00
531b1197a7 Merge pull request #843 from tendermint/refactor-mconnection-with-go-wire-1
WIP: begin parallel refactoring: go-wire Write methods and MConnection
2017-11-22 19:34:22 +00:00
52ad6242f4 Merge pull request #888 from tendermint/rm-dead-file
remove unused file
2017-11-22 18:47:30 +00:00
969b34057b remove unused file 2017-11-22 17:22:53 +00:00
e110f70b5c update glide.yaml versions with go-wire at develop branch 2017-11-22 07:34:10 -08:00
e997db7a23 Merge pull request #859 from tendermint/fix/addrbook
Fix/addrbook
2017-11-21 15:31:48 +00:00
c4b695f78d minor fixes from review 2017-11-21 15:30:19 +00:00
75463b8331 Merge pull request #877 from tendermint/p2p-switch-DialSeeds-undeterministically
p2p: make Switch.DialSeeds use a new PRNG per call
2017-11-21 15:24:29 +00:00
882c25f292 Update getting-started.rst to fix broken link
fixes broken link to introduction.html
2017-11-21 10:11:48 -05:00
9c8100043e made changes to address suggestions from the PR comments 2017-11-20 19:15:11 -05:00
031e10133c p2p: make Switch.DialSeeds use a new PRNG per call
Fixes https://github.com/tendermint/tendermint/issues/875

Ensure that every DialSeeds call uses a new PRNG seeded from
tendermint/tmlibs/common.RandInt which internally uses
crypto/rand to seed its source.
2017-11-20 15:28:42 -07:00
4087326f45 fixed race condition reported in issue #881 2017-11-20 16:47:05 -05:00
f9bc22ec6a p2p: fix comment on addPeer (thanks @odeke-em) 2017-11-20 21:36:01 +00:00
26cd99c66e p2p: fix non-routable addr in test 2017-11-20 19:56:44 +00:00
9334aad906 Merge pull request #871 from tendermint/fix/docs-860
docs: fix links
2017-11-20 19:47:18 +00:00
c695c53259 Merge pull request #876 from tendermint/p2p-extract-key-lex-check-to-variable-for-clarity
p2p: use bytes.Equal for key comparison
2017-11-20 19:33:58 +00:00
5c4397ab30 Run tests on AppVeyor 2017-11-20 13:23:28 +01:00
5c34d087d9 p2p: use bytes.Equal for key comparison
Updates https://github.com/tendermint/tendermint/issues/850

My security alarms falsely blarred when I skimmed and noticed
keys being compared with `==`, without the proper context
so I mistakenly filed an issue, yet the purpose of that
comparison was to check if the local ephemeral public key
was just the least, sorted lexicographically.

Anyways, let's use the proper bytes.Equal check, to save future labor.
2017-11-18 23:34:27 -07:00
559bd169bd docs: fix links, closes #860 2017-11-17 14:03:43 +00:00
f8c969f5a5 Merge pull request #868 from tendermint/small-things
node: clean makeNodeInfo
2017-11-17 01:22:45 +00:00
c5253c7a31 node: clean makeNodeInfo 2017-11-17 01:22:38 +00:00
53f15fde07 update changelog 2017-11-17 00:04:03 +00:00
814f9cb566 Merge pull request #856 from tendermint/small-things
Small things
2017-11-17 00:03:57 +00:00
af0db599b0 minor fixes 2017-11-16 23:57:00 +00:00
104368bd84 Merge pull request #787 from caffix/develop
Initial Trust Metric Implementation
2017-11-16 23:51:53 +00:00
99461a178e Merge pull request #857 from gguoss/patch-1
Failed to compile comment code
2017-11-16 18:35:18 +00:00
feb3230160 some comments 2017-11-16 04:43:07 +00:00
be1a16a601 p2p/pex: simplify ensurePeers 2017-11-16 04:30:38 +00:00
8e044b0e6d p2p/addrbook: some comments 2017-11-16 04:30:23 +00:00
40e93a5f9e p2p/addrbook: fix addToOldBucket 2017-11-16 04:08:46 +00:00
435eb6e2b3 p2p/addrbook: add non-terminating test 2017-11-16 04:04:54 +00:00
8c88cc017a p2p/addrbook: addAddress returns error. more defensive PickAddress 2017-11-16 03:59:54 +00:00
ed95cc160a p2p/addrbook: simplify PickAddress 2017-11-16 02:31:47 +00:00
2f067a3f65 p2p/addrbook: addrNew/Old -> bucketsNew/Old 2017-11-16 02:28:11 +00:00
498a82784d p2p/addrbook: comments 2017-11-16 02:25:00 +00:00
b5708825a7 Failed to compile comment code 2017-11-16 09:45:58 +08:00
a724ffab25 added changes based on PR comments to the proposal 2017-11-15 17:59:48 -05:00
de34ef91d7 Merge pull request #854 from tendermint/add-go-version-to-readme
add Go version badge to README [ci skip]
2017-11-15 20:49:36 +00:00
248a9383a0 add Go version badge to README [ci skip] 2017-11-15 10:22:02 -06:00
78b4ad291c Merge pull request #853 from tendermint/p2p-netPipe-own-file
p2p: netPipe for <Go1.10 in own file with own build tag
2017-11-15 16:09:48 +00:00
3f9dff9aac p2p: netPipe for <Go1.10 in own file with own build tag
Follow up of 283544c7f3
putting <Go1.10 implementation of netPipe in its own
file and protect it with its separate build tag.
2017-11-14 22:23:48 -07:00
443854222c Merge pull request #852 from tendermint/net-conn-SetDeadline-wraps
p2p: use fake net.Pipe since only >=Go1.10 implements SetDeadline
2017-11-15 05:09:39 +00:00
283544c7f3 p2p: use fake net.Pipe since only >=Go1.10 implements SetDeadline
Fixes https://github.com/tendermint/tendermint/issues/851

Go1.9 and below's net.Pipe did not implement the SetDeadline
method so after commit
e2dd8ca946
this problem was exposed since now we check for errors.

To counter this problem, implement a simple composition for
net.Conn that always returns nil on SetDeadline instead of
tripping out.

Added build tags so that anyone using go1.10 when it is released
will be able to automatically use net.Pipe's net.Conns
2017-11-14 22:03:23 -07:00
49faa79bdc Merge pull request #848 from tendermint/p2p-catch-conn.SetDeadline-errors
p2p: peer should respect errors from SetDeadline
2017-11-15 03:34:58 +00:00
7670049a31 Merge pull request #845 from tendermint/fix/826-wait-for-rpc
rpc: wait for rpc servers to be available in tests
2017-11-15 03:29:05 +00:00
0cd642bca7 Merge pull request #849 from tendermint/846-fix-TestFullRound1-race
fix TestFullRound1 race (Refs #846)
2017-11-15 03:27:59 +00:00
fe3c92ecce unescape $NODE_FLAGS (see comment) 2017-11-14 20:56:39 -06:00
a969e24177 crank context timeouts 2017-11-15 01:42:15 +00:00
7b0fa6c889 p2p: peer should respect errors from SetDeadline
Noticed while auditing the code that we aren't respecting
(*net.Conn) SetDeadline errors which return after
a connection has been killed and is simultaneously
being used.

For example given program, without SetDeadline error checks
```go
package main

import (
  "log"
  "net"
  "time"
)

func main() {
  conn, err := net.Dial("tcp", "tendermint.com:443")
  if err != nil {
    log.Fatal(err)
  }
  go func() {
    <-time.After(400 * time.Millisecond)
    conn.Close()
  }()
  for i := 0; i < 5; i++ {
    if err := conn.SetDeadline(time.Now().Add(time.Duration(10 * time.Second))); err != nil {
      log.Fatalf("set deadline #%d, err: %v", i, err)
    }
    log.Printf("Successfully set deadline #%d", i)
    <-time.After(150 * time.Millisecond)
  }
}
```

erraneously gives
```shell
2017/11/14 17:46:28 Successfully set deadline #0
2017/11/14 17:46:29 Successfully set deadline #1
2017/11/14 17:46:29 Successfully set deadline #2
2017/11/14 17:46:29 Successfully set deadline #3
2017/11/14 17:46:29 Successfully set deadline #4
```

However, if we properly fix it to respect that error with
```diff
--- wild.go 2017-11-14 17:44:38.000000000 -0700
+++ main.go 2017-11-14 17:45:40.000000000 -0700
@@ -16,7 +16,9 @@
    conn.Close()
  }()
  for i := 0; i < 5; i++ {
-   conn.SetDeadline(time.Now().Add(time.Duration(10 * time.Second)))
+   if err := conn.SetDeadline(time.Now().Add(time.Duration(10 *
time.Second))); err != nil {
+     log.Fatalf("set deadline #%d, err: %v", i, err)
+   }
    log.Printf("Successfully set deadline #%d", i)
    <-time.After(150 * time.Millisecond)
  }
```

properly catches any problems and gives
```shell
$ go run main.go
2017/11/14 17:43:44 Successfully set deadline #0
2017/11/14 17:43:45 Successfully set deadline #1
2017/11/14 17:43:45 Successfully set deadline #2
2017/11/14 17:43:45 set deadline #3, err: set tcp 10.182.253.51:57395:
use of closed network connection
exit status 1
```
2017-11-14 18:01:51 -07:00
fa60d8120e fix TestFullRound1 race (Refs #846)
```
==================
WARNING: DATA RACE
Write at 0x00c42d7605f0 by goroutine 844:
  github.com/tendermint/tendermint/consensus.(*ConsensusState).updateToState()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:465 +0x59e
I[11-14|22:37:28.781] Added to prevote                             vote="Vote{0:646753DCE124 1/02/1(Prevote) E9B19636DCDB {/CAD5FA805E8C.../}}" prevotes="VoteSet{H:1 R:2 T:1 +2/3:<nil> BA{2:X_} map[]}"
  github.com/tendermint/tendermint/consensus.(*ConsensusState).finalizeCommit()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1229 +0x16a9
  github.com/tendermint/tendermint/consensus.(*ConsensusState).tryFinalizeCommit()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1135 +0x721
  github.com/tendermint/tendermint/consensus.(*ConsensusState).enterCommit.func1()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1087 +0x153
  github.com/tendermint/tendermint/consensus.(*ConsensusState).enterCommit()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1114 +0xa34
  github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1423 +0xdd6
  github.com/tendermint/tendermint/consensus.(*ConsensusState).tryAddVote()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:1317 +0x77
  github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:565 +0x7a9
  github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:523 +0x6d2

Previous read at 0x00c42d7605f0 by goroutine 654:
  github.com/tendermint/tendermint/consensus.validatePrevote()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/common_test.go:149 +0x57
  github.com/tendermint/tendermint/consensus.TestFullRound1()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state_test.go:256 +0x3c5
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:746 +0x16c

Goroutine 844 (running) created at:
  github.com/tendermint/tendermint/consensus.(*ConsensusState).startRoutines()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state.go:258 +0x8c
  github.com/tendermint/tendermint/consensus.startTestRound()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/common_test.go:118 +0x63
  github.com/tendermint/tendermint/consensus.TestFullRound1()
      /home/vagrant/go/src/github.com/tendermint/tendermint/consensus/state_test.go:247 +0x1fb
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:746 +0x16c

Goroutine 654 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:789 +0x568
  testing.runTests.func1()
      /usr/local/go/src/testing/testing.go:1004 +0xa7
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:746 +0x16c
  testing.runTests()
      /usr/local/go/src/testing/testing.go:1002 +0x521
  testing.(*M).Run()
      /usr/local/go/src/testing/testing.go:921 +0x206
  main.main()
      github.com/tendermint/tendermint/consensus/_test/_testmain.go:106 +0x1d3
==================
```
2017-11-14 17:41:30 -06:00
8b7649b90c enhancements made in response to PR full review comments 2017-11-14 18:26:06 -05:00
687834c99e added initial trust metric test routines 2017-11-14 18:26:06 -05:00
54c25ccbf5 integrated trust metric store as per PR comments 2017-11-14 18:26:06 -05:00
e160a6198c added initial trust metric design doc and code 2017-11-14 18:26:06 -05:00
e69d36d54f some more robust sleeps 2017-11-14 22:31:23 +00:00
844c43e044 use stdlib context 2017-11-14 22:30:00 +00:00
194712fd3b rpc: wait for rpc servers to be available in tests 2017-11-14 21:51:49 +00:00
30f675aafa Merge pull request #839 from tendermint/bugfix/pubsub-failures
Fix nondeterministic tests failures related to pubsub
2017-11-14 18:13:47 +00:00
695266e907 Merge pull request #844 from tendermint/bunch-up-p2p.AddrBook-wg-calls
p2p: comment on the wg.Add before go saveRoutine()
2017-11-14 17:18:27 +00:00
3db44dacae Merge pull request #840 from tendermint/fix/tests
Fix/tests
2017-11-14 15:48:17 +00:00
62c1bc0a20 p2p: comment on the wg.Add before go saveRoutine()
Just noticed while auditing the code in p2p/addrbook.go,
wg.Add(1) but no subsequent defer.
@jaekwon and I had a discussion offline and we agreed to
comment about why the code was that way and why
we shouldn't move the wg.Add(1) into .saveRoutine() because
if go a.saveRoutine() isn't started before anyone invokes
a.Wait(), then we'd have raced a.saveRoutine().
2017-11-13 18:14:58 -07:00
3863885c71 WIP: begin parallel refactoring with go-wire Write methods and MConnection 2017-11-12 22:11:15 -08:00
238e2b72ee Merge pull request #834 from tendermint/829-enable-logs-by-default
Enable logs by default
2017-11-12 07:06:14 +00:00
a65ab3b0e0 Merge pull request #838 from tendermint/docker
docker update || 0.12.0
2017-11-12 06:51:01 +00:00
aba8a8f4fc consensus: crank timeout in timeoutWaitGroup 2017-11-12 06:41:15 +00:00
0448c2b437 consensus: fix LastCommit log 2017-11-12 06:40:27 +00:00
0ada0cf525 certifiers: test uses WaitForHeight 2017-11-12 00:43:16 +00:00
7fa12662c4 check whatever we can read from the channel
```
panic: interface conversion: interface {} is nil, not types.TMEventData

goroutine 7690 [running]:
github.com/tendermint/tendermint/consensus.waitForAndValidateBlock.func1(0xc427727620, 0x3)
        /go/src/github.com/tendermint/tendermint/consensus/reactor_test.go:292 +0x62b
created by github.com/tendermint/tendermint/consensus.timeoutWaitGroup
        /go/src/github.com/tendermint/tendermint/consensus/reactor_test.go:349 +0xa4
exit status 2
FAIL    github.com/tendermint/tendermint/consensus      38.614s

```
2017-11-10 18:16:31 -05:00
bc9c4e8dee update readme [ci skip] 2017-11-10 15:38:32 -05:00
8004af2519 update docker readme 2017-11-10 15:17:13 -05:00
21e87ebc11 update Go version to 1.9.2 2017-11-10 15:10:52 -05:00
70d8afa6e9 update Dockerfile 2017-11-10 15:09:38 -05:00
847f865438 Merge pull request #836 from tendermint/fix/tests
consensus: make mempool_test deterministic
2017-11-10 05:08:54 +00:00
2cda777900 consensus: make mempool_test deterministic 2017-11-09 23:54:02 +00:00
432a7276e2 [test_integrations] enable logs from peers by default (Refs #829) 2017-11-09 15:19:49 -05:00
533f7c45eb fix bash linter warnings for atomic_broadcast integration test 2017-11-09 14:58:16 -05:00
a1cdc2b68a set logger for peer's MConnection 2017-11-09 14:57:40 -05:00
9c4d533695 Merge pull request #833 from tendermint/fix/consensus-tests
consensus: fix for initializing block parts during catchup
2017-11-09 19:04:21 +00:00
ad03491ee6 remove duplicated key 2017-11-09 13:37:29 -05:00
4b9dfc8990 consensus: fix for initializing block parts during catchup 2017-11-09 18:14:41 +00:00
a46f64cd1e Merge pull request #824 from tendermint/bugfix/node_test
rewrite node test to use new pubsub
2017-11-09 01:35:35 +00:00
b1e7163689 rewrite node test to use new pubsub 2017-11-08 13:12:48 -05:00
c931279960 p2p: some fixes re @odeke-em issues #813,#816,#817 2017-11-08 17:54:29 +00:00
12b25fdf6e blockchain: add comment in AddPeer. closes #666 2017-11-08 02:42:27 +00:00
c0e2649ed6 Merge pull request #788 from tendermint/feature/548-indexing-tags
new pubsub package
2017-11-08 01:02:48 +00:00
593c127257 rpc/lib/types: RPCResponse.Result is not a pointer 2017-11-08 01:00:15 +00:00
9f6a09277e Merge pull request #812 from tendermint/808-make-connected-switches
MakeConnectedSwitches: connect first switch to others
2017-11-08 00:54:23 +00:00
dd47884661 Merge pull request #820 from tendermint/790-use-tickers-instead-of-time-Sleep
prefer tickers to time.Sleep
2017-11-08 00:53:42 +00:00
a01c226dc4 wsConnection: call onDisconnect 2017-11-07 19:22:01 -05:00
47f5e37205 copy RoundState for event 2017-11-07 23:57:23 +00:00
51c9211cf4 add test for MConnection TrySend and Send 2017-11-07 23:35:25 +00:00
7869e541f6 change MakeConnectedSwitches to not connect to itself
and a test for it
2017-11-07 18:33:00 -05:00
e0daca5693 fixes from Bucky's review 2017-11-07 18:20:24 -05:00
e8e512f1fa Merge pull request #815 from tendermint/p2p-readme-tests
P2P: readme and tests
2017-11-07 23:01:15 +00:00
37ce171061 p2p/connetion: remove panics, test error cases 2017-11-07 23:00:52 +00:00
e01986e2b3 p2p: update readme, some minor things 2017-11-07 23:00:49 +00:00
433416fef8 Merge pull request #818 from tendermint/fix/810-stuck-trailing-node
consensus: ensure prs.ProposalBlockParts is initialized. fixes #810
2017-11-07 21:52:08 +00:00
2d4ad02356 prefer tickers to time.Sleep (Refs #790) 2017-11-07 15:38:25 -05:00
3b81d3fea4 consensus: ensure prs.ProposalBlockParts is initialized. fixes #810 2017-11-07 17:14:40 +00:00
e785697a64 connect first switch to others (Refs #808) 2017-11-06 23:43:40 -05:00
4ffe9304ba unsubscribe from all subscriptions on WS disconnect 2017-11-02 14:00:18 -05:00
b1eec3a5d3 remove test_data/empty_block and test_data/small_blockN 2017-11-02 13:20:14 -05:00
fcdd30b2d3 fixes from Bucky's review 2 2017-11-02 13:20:05 -05:00
ec87c740a7 Merge pull request #794 from tendermint/243-restart-app-via-os
Kill Tendermint when App dies
2017-10-31 16:27:23 -04:00
6b737d2c1b Merge pull request #745 from tendermint/test-rpc-server-handlers
rpc/lib/server: add handlers tests for params inclusion
2017-10-31 15:42:24 -04:00
f7f4ba5e90 rpc/lib/server: minor changes to test 2017-10-31 15:41:25 -04:00
5466720d75 minor changes from @odeke-em PR #725 2017-10-31 15:32:07 -04:00
7c3cf316f1 rpc/wsevents: small cleanup 2017-10-31 15:16:08 -04:00
d71aed309f some minor changes 2017-10-30 22:52:03 -04:00
d6beb60bf7 Merge pull request #799 from petabytestorage/fix-typo-switch-comment
fix comment typos
2017-10-30 18:01:32 -04:00
61d76a273f fixes from Bucky's and Emmanuel's reviews 2017-10-30 11:12:01 -05:00
6d18e2f447 do not send whole round state via eventHub
Fixes

```
WARNING: DATA RACE
Write at 0x00c4200715b8 by goroutine 24:
  github.com/tendermint/tendermint/consensus.(*ConsensusState).enterPrevote.func1()
      /go/src/github.com/tendermint/tendermint/consensus/state.go:359 +0x3f
  github.com/tendermint/tendermint/consensus.(*ConsensusState).enterPrevote()
      /go/src/github.com/tendermint/tendermint/consensus/state.go:897 +0x8de
  github.com/tendermint/tendermint/consensus.(*ConsensusState).addProposalBlockPart()
      /go/src/github.com/tendermint/tendermint/consensus/state.go:1303 +0x701
  github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg()
      /go/src/github.com/tendermint/tendermint/consensus/state.go:560 +0x88c
  github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine()
      /go/src/github.com/tendermint/tendermint/consensus/state.go:525 +0x6d2

Previous read at 0x00c4200715b8 by goroutine 19:
  github.com/tendermint/tendermint/consensus.makeRoundStepMessages()
      /go/src/github.com/tendermint/tendermint/consensus/reactor.go:415 +0x192
  github.com/tendermint/tendermint/consensus.(*ConsensusReactor).broadcastNewRoundStep()
      /go/src/github.com/tendermint/tendermint/consensus/reactor.go:377 +0x3c
  github.com/tendermint/tendermint/consensus.(*ConsensusReactor).broadcastNewRoundStepsAndVotes.func1()
      /go/src/github.com/tendermint/tendermint/consensus/reactor.go:350 +0x275
```
2017-10-30 00:32:23 -05:00
1c1c68df8d fixes from my own review 2017-10-30 00:32:23 -05:00
f6539737de new pubsub package
comment out failing consensus tests for now

rewrite rpc httpclient to use new pubsub package

import pubsub as tmpubsub, query as tmquery

make event IDs constants
EventKey -> EventTypeKey

rename EventsPubsub to PubSub

mempool does not use pubsub

rename eventsSub to pubsub

new subscribe API

fix channel size issues and consensus tests bugs

refactor rpc client

add missing discardFromChan method

add mutex

rename pubsub to eventBus

remove IsRunning from WSRPCConnection interface (not needed)

add a comment in broadcastNewRoundStepsAndVotes

rename registerEventCallbacks to broadcastNewRoundStepsAndVotes

See https://dave.cheney.net/2014/03/19/channel-axioms

stop eventBuses after reactor tests

remove unnecessary Unsubscribe

return subscribe helper function

move discardFromChan to where it is used

subscribe now returns an err

this gives us ability to refuse to subscribe if pubsub is at its max
capacity.

use context for control overflow

cache queries

handle err when subscribing in replay_test

rename testClientID to testSubscriber

extract var

set channel buffer capacity to 1 in replay_file

fix byzantine_test

unsubscribe from single event, not all events

refactor httpclient to return events to appropriate channels

return failing testReplayCrashBeforeWriteVote test

fix TestValidatorSetChanges

refactor code a bit

fix testReplayCrashBeforeWriteVote

add comment

fix TestValidatorSetChanges

fixes from Bucky's review

update comment [ci skip]

test TxEventBuffer

update changelog

fix TestValidatorSetChanges (2nd attempt)

only do wg.Done when no errors

benchmark event bus

create pubsub server inside NewEventBus

only expose config params (later if needed)

set buffer capacity to 0 so we are not testing cache

new tx event format: key = "Tx" plus a tag {"tx.hash": XYZ}

This should allow to subscribe to all transactions! or a specific one
using a query: "tm.events.type = Tx and tx.hash = '013ABF99434...'"

use TimeoutCommit instead of afterPublishEventNewBlockTimeout

TimeoutCommit is the time a node waits after committing a block, before
it goes into the next height. So it will finish everything from the last
block, but then wait a bit. The idea is this gives it time to hear more
votes from other validators, to strengthen the commit it includes in the
next block. But it also gives it time to hear about new transactions.

waitForBlockWithUpdatedVals

rewrite WAL crash tests

Task:
test that we can recover from any WAL crash.

Solution:
the old tests were relying on event hub being run in the same thread (we
were injecting the private validator's last signature).

when considering a rewrite, we considered two possible solutions: write
a "fuzzy" testing system where WAL is crashing upon receiving a new
message, or inject failures and trigger them in tests using something
like https://github.com/coreos/gofail.

remove sleep

no cs.Lock around wal.Save

test different cases (empty block, non-empty block, ...)

comments

add comments

test 4 cases: empty block, non-empty block, non-empty block with smaller part size, many blocks

fixes as per Bucky's last review

reset subscriptions on UnsubscribeAll

use a simple counter to track message for which we panicked

also, set a smaller part size for all test cases
2017-10-30 00:32:22 -05:00
fe9ff62297 fix comment typos 2017-10-28 22:01:45 -07:00
7c85f15a6c Merge pull request #798 from petabytestorage/fix-test-uncommon-names
fix test using uncommon names
2017-10-28 23:47:31 -04:00
6b366b2443 fix test using uncommon names 2017-10-28 20:29:11 -07:00
a8b77359df rpc/lib/server: separate out Notifications test
Addressing feedback from @ebuchman
2017-10-28 15:24:40 -07:00
e7fab7d4bf rpc/lib/server: update with @melekes and @ebuchman feedback 2017-10-28 15:11:21 -07:00
59556ab030 rpc/lib/server: add handlers tests
Follow up of PR https://github.com/tendermint/tendermint/pull/724
For https://github.com/tendermint/tendermint/issues/708

Reported initially in #708, this bug was reconfirmed
by the fuzzer.

This fix ensures that:
* if the user doesn't pass in `"id"` that we send them back
a message in an error telling them to send `"id"`. Previously
we let the handler return a 200 with nothing.
* passing in nil `params` doesn't crash
* not passing in `params` doesn't crash
* passing in non-JSON parseable data to `params` doesn't crash
2017-10-28 15:11:21 -07:00
128e2a1d9e Merge branch 'master' into develop 2017-10-28 00:09:03 -04:00
e236302256 Merge pull request #793 from tendermint/release-v0.12.0
Release v0.12.0
2017-10-28 00:06:53 -04:00
dfe28c8855 test: update for abci-cli consolidation. shell formatting 2017-10-27 23:09:50 -04:00
4b616344fa update glide, again 2017-10-27 22:36:03 -04:00
1ecd580061 Merge pull request #773 from tendermint/docs-staging
docs improvements
2017-10-27 16:18:56 -04:00
21dcb4f290 update glide 2017-10-27 13:55:56 -04:00
b2b35d7dc1 update changelog 2017-10-27 11:54:20 -04:00
a1501dcde8 version bump 2017-10-27 11:54:20 -04:00
3319ad03b8 Merge pull request #791 from tendermint/740-no-wal-after-fast-sync
dont catchupReplay on wal if we fast synced
2017-10-27 11:49:54 -04:00
fe1c60b5cf consensus: kill process on app error 2017-10-27 10:55:20 -04:00
591dd9e662 dont catchupReplay on wal if we fast synced 2017-10-27 10:46:19 -04:00
bb6c15b00a CHANGELOG [ci skip] 2017-10-26 09:42:46 -04:00
6af28ead87 Merge pull request #672 from tendermint/573-wal-issues
Add checksum and length to CS WAL record
2017-10-26 00:31:38 -04:00
fcf459158d CHANGELOG [ci skip] 2017-10-26 00:29:58 -04:00
e76ef2a8a1 types: unexpose valset.To/FromBytes 2017-10-26 00:27:02 -04:00
3c92bea519 glide: more external deps locked to versions 2017-10-26 00:07:43 -04:00
12c703c1c3 Merge branch 'develop' into 573-wal-issues 2017-10-25 23:56:08 -04:00
376f47e030 Merge pull request #775 from tendermint/rpc-client-jitter
rpc/lib/client: add jitter for exponential backoff of WSClient
2017-10-25 22:53:50 -04:00
ceedd4d968 remove unnecessary plus [ci skip] 2017-10-25 22:28:20 -04:00
c595636999 glide 2017-10-25 22:23:55 -04:00
6e5cd10399 rpc/lib/client: jitter test updates and only to-be run on releases
* Updated code with feedback from @melekes, @ebuchman and @silasdavis.
* Added Makefile clause `release` to only run the test on seeing tag
`release` during releases i.e
```shell
make release
```
which will run the comprehensive and long integration-ish tests.
2017-10-25 19:20:55 -07:00
57a684d5ac fixes from review 2017-10-25 21:54:56 -04:00
5534eb4707 Merge pull request #776 from tendermint/feature/merge-light-client
Merge light client
2017-10-25 16:12:39 -04:00
b2d5546cf8 Merge pull request #777 from silasdavis/fix-blocking-ws-client
Fix WSClient deadlock in the readRoutine after Stop() is called
2017-10-25 11:00:30 -04:00
f653ba63bf Separated out certifiers.Commit from rpc structs 2017-10-25 16:43:18 +02:00
0396b6d521 Rename checkpoint.go 2017-10-25 16:13:04 +02:00
94b36bb65e Move VerifyCommitAny into the types package 2017-10-25 16:13:04 +02:00
b4fd6e876e Copy certifiers from light-client 2017-10-25 16:13:04 +02:00
775e100d2c Merge pull request #783 from tendermint/782-tendermint-invalid-command-panics
fix panic: failed to determine gopath: exec: "go"
2017-10-25 08:50:16 -04:00
4cb02d0bf2 Exploit the fact the BaseService's closed Quit channel will keep emitting quit signals to close both readRoutine and writeRoutine 2017-10-25 10:19:18 +01:00
ae538337ba fix panic: failed to determine gopath: exec: "go" (Refs #782)
```
-bash-4.2$ tendermint show_validators
panic: failed to determine gopath: exec: "go": executable file not found in $PATH

goroutine 1 [running]:
github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.gopath(0xc4200632c0, 0x18)
	/var/lib/jenkins/workspace/03.Build.Package/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/os.go:26 +0x1b5
github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.init()
	/var/lib/jenkins/workspace/03.Build.Package/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/os.go:17 +0x13c
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.init()
	/var/lib/jenkins/workspace/03.Build.Package/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/wire.go:165 +0x50
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/data.init()
	/var/lib/jenkins/workspace/03.Build.Package/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/data/wrapper.go:89 +0x50
github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli.init()
	/var/lib/jenkins/workspace/03.Build.Package/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli/setup.go:190 +0x76
main.init()
	/var/lib/jenkins/workspace/03.Build.Package/go/src/github.com/tendermint/tendermint/cmd/tendermint/main.go:42 +0x49```

An error message instead would be nice.
```

Now GoPath() is a function instead of a variable.
2017-10-25 11:19:53 +04:00
62a7beec21 Merge pull request #780 from ericdmann/769-error-msg-while-testnet-sync
Change log level to Info when proposal block hashing fails
2017-10-24 23:27:20 -04:00
45e18a1832 Change log level to Info when proposal block hashing fails due to partially complete block 2017-10-24 14:13:35 -07:00
f6adddb4a8 Replace ResultsCh with ResponsesCh 2017-10-24 17:45:13 +01:00
38fc351532 Merge pull request #765 from tendermint/762-blockchain-reactor-timeout
blockchain reactor timeout
2017-10-24 09:13:26 -04:00
01be6fa309 Fix WSClient blocking in the readRoutine after Stop() as it tries to write to ResultsCh 2017-10-24 13:31:24 +01:00
e06bbaf303 refactor TestNoBlockMessageResponse to eliminate a race condition 2017-10-24 15:32:01 +04:00
bb7b152af5 write docs for cutWALUntil and wal2json binaries 2017-10-24 13:25:47 +04:00
5504920ba3 rpc/lib/client: add jitter for exponential backoff of WSClient
Fixes https://github.com/tendermint/tendermint/issues/751.

Adds jitter to our exponential backoff to mitigate a self DDOS
vector. The jitter is a randomly picked percentage of a second
whose purpose is to ensure that each exponential backoff retry
occurs within (1<<attempts) == 2**attempts, but with the delay
each client will have a random buffer time before it tries to
reconnect instead of all at once reconnections that might even
bring back the previous conditions that might have caused the
dial to the WSServer to have failed e.g
* Network outage
* File descriptor exhaustion
* False positives from firewalls
etc
2017-10-24 02:00:20 -07:00
c74a359c46 fixes per Bucky's review 2017-10-24 12:14:21 +04:00
ee9dc6ce59 docs: fixup abci guide 2017-10-23 20:56:49 -04:00
62e8ec34d1 fix comment, #723 2017-10-23 19:51:09 -04:00
6a5254c475 Added local blockchain sync benchmark script 2017-10-23 19:46:57 -04:00
2802a06a08 blockchain/store: comment about panics 2017-10-23 19:46:14 -04:00
8ac430813d Merge pull request #772 from tendermint/docs/flow
moar docs updates
2017-10-23 19:14:06 -04:00
3e61b8c17a docs: comb through step by step 2017-10-23 19:11:51 -04:00
9e277d1596 docs: smaller logo (200px) 2017-10-23 17:34:27 -04:00
4c9d5244a5 Merge pull request #759 from tendermint/improve-docs
docs: update abci example details
2017-10-23 17:29:34 -04:00
87cc277b38 Merge pull request #721 from tendermint/564-add-app-options-to-genesis-resp
Add app_options to GenesisDoc
2017-10-23 16:03:45 -04:00
3115c23762 binary format for WAL 2017-10-23 22:27:24 +04:00
31030c6514 make crc32c a global var
change echo format in build.sh script
2017-10-23 22:09:42 +04:00
7b8ffc9981 add checksum and msg size to TimedWALMessage
updated test_data/build.sh script
2017-10-23 22:09:17 +04:00
a75bccfbc4 Merge branch 'develop' into 564-add-app-options-to-genesis-resp 2017-10-23 11:30:00 -04:00
f97229f05a Merge pull request #748 from tendermint/params-test
types: ConsensusParams test + document the ranges/limits
2017-10-23 11:18:00 -04:00
ac2ef9e0ea Merge pull request #750 from tendermint/feature/cleanup
Cleanup of code and code docs
2017-10-23 11:14:15 -04:00
c2803b80e8 update changelog; fixes from rebase 2017-10-23 11:13:12 -04:00
7a6876bc62 Merge pull request #768 from tendermint/feature/merkleeyes-to-iavl
Feature/merkleeyes to iavl
2017-10-23 11:07:21 -04:00
819f81f702 Change NOTE to CONTRACT 2017-10-23 11:04:45 -04:00
036d3b59a3 Address reviews 2017-10-23 11:04:45 -04:00
782a836db0 Cleanup of code and code docs
This cleans up some of the code in the state package
2017-10-23 11:04:45 -04:00
bd46b78785 Merge pull request #755 from tendermint/753-notified-mempool-txs-but-mempool-empty
WIP: only notify when there are some txs (Refs #753)
2017-10-23 10:31:38 -04:00
f908dd0e55 only notify when there are some txs (Refs #753) 2017-10-23 10:31:00 -04:00
0bbf38141a blockchain/pool: some comments and small changes 2017-10-23 10:13:46 -04:00
f188366e26 update glide 2017-10-23 10:04:00 -04:00
fd60621a8e update cswal test 2017-10-23 10:03:54 -04:00
60b7f2c61b Merge pull request #767 from silasdavis/do-not-swallow
Make RPCError an actual error and don't swallow its companion data
2017-10-23 01:51:40 -04:00
3e3d53daef Make RPCError an actual error and don't swallow its companion data 2017-10-22 15:14:21 +01:00
d64a48e0ee set logger on blockchain pool 2017-10-20 23:56:21 +04:00
0a7b2ab52c fix invalid memory address or nil pointer dereference error (Refs #762)
https://github.com/tendermint/tendermint/issues/762#issuecomment-338276055
```
E[10-19|04:52:38.969] Stopping peer for error                      module=p2p peer="Peer{MConn{178.62.46.14:46656} B14916FAF38A out}" err="Error: runtime error: invalid memory address or nil pointer dereference\nStack: goroutine 529485 [running]:\nruntime/debug.Stack(0xc4355cfb38, 0xb463e0, 0x11b1c30)\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0xa7\ngithub.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/p2p.(*MConnection)._recover(0xc439a28870)\n\t/home/ubuntu/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/p2p/connection.go:206 +0x6e\npanic(0xb463e0, 0x11b1c30)\n\t/usr/local/go/src/runtime/panic.go:491 +0x283\ngithub.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/blockchain.(*bpPeer).decrPending(0x0, 0x381)\n\t/home/ubuntu/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/blockchain/pool.go:376 +0x22\ngithub.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/blockchain.(*BlockPool).AddBlock(0xc4200e4000, 0xc4266d1f00, 0x40, 0xc432ac9640, 0x381)\n\t/home/ubuntu/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/blockchain/pool.go:215 +0x139\ngithub.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/blockchain.(*BlockchainReactor).Receive(0xc42050a780, 0xc420257740, 0x1171be0, 0xc42ff302d0, 0xc4384b2000, 0x381, 0x1000)\n\t/home/ubuntu/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/blockchain/reactor.go:160 +0x712\ngithub.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/p2p.createMConnection.func1(0x11e5040, 0xc4384b2000, 0x381, 0x1000)\n\t/home/ubuntu/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/p2p/peer.go:334 +0xbd\ngithub.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/p2p.(*MConnection).recvRoutine(0xc439a28870)\n\t/home/ubuntu/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/p2p/connection.go:475 +0x4a3\ncreated by github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/p2p.(*MConnection).OnStart\n\t/home/ubuntu/go/src/github.com/cosmos/gaia/vendor/github.com/tendermint/tendermint/p2p/connection.go:170 +0x187\n"
```
2017-10-20 21:56:10 +04:00
8a69f1087b docs: typo 2017-10-20 07:56:26 -04:00
f24f03906f types: ConsensusParams: add feedback from @ebuchman and @melekes 2017-10-20 00:11:30 -06:00
fa56e8c0ce Merge pull request #676 from tendermint/state-unexpose-genesisDoc-chainID
all, state: unexpose GenesisDoc, ChainID fields make them accessor methods
2017-10-18 20:10:02 -04:00
fc406d1657 docs: update abci example details [ci skip] 2017-10-18 16:33:37 -04:00
9dcefd0e1e Merge pull request #754 from tendermint/improve-docs
add tm-migrator to docs
2017-10-18 13:04:12 -04:00
a2dc53d43d Merge pull request #757 from tendermint/756-specification-validators
correct an error in validator's specification [ci skip] (Refs #756)
2017-10-18 13:02:13 -04:00
b9c4fab96e correct an error in validator's specification [ci skip] (Refs #756) 2017-10-18 19:23:30 +04:00
fa07dbd7ec docs: add info about tm-migrate 2017-10-18 08:47:58 -04:00
9b382d7a11 docs: remove mention of type byte 2017-10-18 08:00:01 -04:00
75b78bfb72 panic on marshal/unmarshal failures for genesisDoc 2017-10-17 13:33:57 +04:00
b234f7aba2 Merge pull request #741 from tendermint/client-compile-time-assertions
rpc/client: use compile time assertions instead of methods
2017-10-17 03:41:24 -04:00
bff069f83c types: ConsensusParams test + document the ranges/limits
Fixes https://github.com/tendermint/tendermint/issues/747
Updates https://github.com/tendermint/tendermint/issues/693

* Document the unmentioned limits for ConsensusParams.Validate()
* Make the limit for ConsensusParams.BlockSizeParams.MaxBytes
clear at 100MiB
2017-10-16 16:57:44 -06:00
616b07ff6b make AppOptions an interface{} 2017-10-16 10:58:52 +04:00
b26f812399 update changelog 2017-10-16 10:58:52 +04:00
321061125f add app_options to GenesisDoc (Refs #564) 2017-10-16 10:58:52 +04:00
6469e2ccca save genesis doc in DB to prevent user errors
https://github.com/tendermint/tendermint/pull/676#discussion_r144411458
2017-10-16 10:51:58 +04:00
c4646bf87f make state#Params not a pointer
also remove the comment
2017-10-16 10:34:02 +04:00
716364182d [state] expose ChainID and Params
```
jaekwon
Yeah we should definitely expose ChainID.
ConsensusParams is small enough, we can just write it.
```
https://github.com/tendermint/tendermint/pull/676#discussion_r144123203
2017-10-16 10:34:02 +04:00
1971e149fb ChainID() and Params() do not return errors
- remove state#GenesisDoc() method
2017-10-16 10:34:02 +04:00
7939d62ef0 all, state: unexpose GenesisDoc, ChainID fields make them accessor methods
Fixes #671

Unexpose GenesisDoc and ChainID fields to avoid them being
serialized to the DB on every block write/state.Save()

A GenesisDoc can now be alternatively written to the state's
database, by serializing its JSON as a value of key "genesis-doc".

There are now accessors and a setter for these attributes:
- state.GenesisDoc() (*types.GenesisDoc, error)
- state.ChainID() (string, error)
- state.SetGenesisDoc(*types.GenesisDoc)

This is a breaking change since it changes how the state's
serialization and requires that if loading the GenesisDoc entirely
from the database, you'll need to set its value in the database
as the GenesisDoc's JSON marshaled bytes.
2017-10-16 10:34:01 +04:00
4c1f1e4e57 Merge pull request #746 from srmo/701-add-dev-docs-in-java
701 add dev docs in java
2017-10-15 11:02:36 -04:00
09170f76fe Merge pull request #743 from tendermint/zramsay-patch-1
Update getting-started.rst
2017-10-15 11:01:19 -04:00
9e1edf8685 [docs] add Java examples for each section 2017-10-15 13:45:43 +02:00
e7fe299504 [docs] replace all GO snippets with collapsible blocks 2017-10-15 12:21:06 +02:00
b90edffe28 [docs] add first java block for deliverTx 2017-10-15 12:00:08 +02:00
f361092ed9 [docs] provide means to have collapsible code blocks without adding a new theme 2017-10-15 11:59:37 +02:00
a1e0f0ba95 docs/ecosystem: add py-tendermint to abci-servers 2017-10-14 00:59:34 -04:00
5f218a43fd rpc/client: use compile time assertions instead of methods 2017-10-13 14:30:54 -06:00
7fe470fc76 Update getting-started.rst 2017-10-13 14:50:54 -04:00
d490c25807 Merge pull request #720 from tendermint/types-heartbeat-test
types/heartbeat: test all Heartbeat functions
2017-10-13 09:22:59 -04:00
340f33b475 Merge pull request #734 from tendermint/482-support-historical-abci-queries
support historical abci queries
2017-10-13 09:14:32 -04:00
7518c4a9be [rpc] update comment [ci skip] 2017-10-13 15:03:21 +04:00
db413aadfd fixes from @cloudhead review 2017-10-13 15:03:21 +04:00
5433e5771e support historical abci queries (Refs #482) 2017-10-13 15:03:20 +04:00
e2e50bc0fc rpc: use /iavl repo in test (#713) 2017-10-11 10:35:22 -04:00
27245ce6f6 Merge branch 'master' into develop 2017-10-10 19:12:40 -04:00
d4634dc683 Merge pull request #729 from tendermint/release/0.11.1
Release/0.11.1
2017-10-10 18:50:15 -04:00
8c08fc671c fix version 2017-10-10 18:49:08 -04:00
a2d40580d7 Merge pull request #732 from sbellem/docs-install-typo-fix
[docs: typo fix] add missing "have"
2017-10-10 11:22:39 -04:00
0011af7adf Merge pull request #727 from sbellem/docs-typo-fix
[docs:typo fix] remove misplaced "the"
2017-10-10 11:20:34 -04:00
1764106606 [docs: typo fix] add missing "have" 2017-10-10 17:15:35 +02:00
3356544706 update changelog 2017-10-10 11:10:48 -04:00
335e012b6a Merge branch 'develop' into release/0.11.1 2017-10-10 11:08:14 -04:00
a458da8f92 Merge pull request #724 from tendermint/708-leaving-out-params-crashes-tm-rpc
Leaving out params crashes tm rpc
2017-10-10 10:53:21 -04:00
9fb45c5b5a remove a stale comment 2017-10-10 10:52:26 -04:00
aae4e94998 make RPCRequest params not a pointer
https://github.com/tendermint/tendermint/pull/724#issuecomment-335362927
2017-10-10 13:50:06 +04:00
d935a4f0a8 recover from panic in WS JSON RPC readRoutine
https://github.com/tendermint/tendermint/pull/724#issuecomment-335316484
2017-10-10 13:48:56 +04:00
5c331d8276 log a notification to help debug user issues 2017-10-10 13:01:25 +04:00
13b9de6778 return missing package declaration 2017-10-10 12:48:36 +04:00
dc0e8de9b0 extract some of the consensus types into ./types
so they can be used in rpc/core/types/responses.go.

```
So, it seems like we could use the actual structs here, but we don't want to have to import consensus to get them, as then clients are importing too much crap. So probably we should move some types from consensus into consensus/types so we can import.

Will these raw messages be identical to:

type ResultDumpConsensusState struct {
  RoundState cstypes.RoundState
  PeerRoundStates map[string]cstypes.PeerRoundState
}
```
https://github.com/tendermint/tendermint/pull/724#discussion_r143598193
2017-10-10 12:39:21 +04:00
90a2335267 bump version to 0.11.1 2017-10-10 01:18:33 +04:00
99c4e48038 return missing package declaration 2017-10-10 01:14:42 +04:00
4bd4d59af5 update changelog [ci skip] 2017-10-10 01:14:00 +04:00
8219abc552 [docs:typo fix] remove misplaced "the" 2017-10-09 20:06:43 +02:00
d6a87d3c43 [rpc] DumpConsensusState: output state as json rather than string
Before:

```
{
  "jsonrpc": "2.0",
  "id": "",
  "result": {
    "round_state": "RoundState{\n  H:10 R:0 S:RoundStepNewHeight\n  StartTime:     2017-10-09 13:07:24.841134374 +0400 +04\n  CommitTime:    2017-10-09 13:07:23.841134374 +0400 +04\n  Validators:    ValidatorSet{\n      Proposer: Validator{EF243CC0E9B88D0161D24D733BDE9003518CEA27 {PubKeyEd25519{2E0B9301334FCDAB193D514022F81BA09BBEC028685C96602BE9DD0BD4F9E202}} VP:10 A:0}\n      Validators:\n        Validator{EF243CC0E9B88D0161D24D733BDE9003518CEA27 {PubKeyEd25519{2E0B9301334FCDAB193D514022F81BA09BBEC028685C96602BE9DD0BD4F9E202}} VP:10 A:0}\n    }\n  Proposal:      \u003cnil\u003e\n  ProposalBlock: nil-PartSet nil-Block\n  LockedRound:   0\n  LockedBlock:   nil-PartSet nil-Block\n  Votes:         HeightVoteSet{H:10 R:0~0\n      VoteSet{H:10 R:0 T:1 +2/3:\u003cnil\u003e BA{1:_} map[]}\n      VoteSet{H:10 R:0 T:2 +2/3:\u003cnil\u003e BA{1:_} map[]}\n    }\n  LastCommit: VoteSet{H:9 R:0 T:2 +2/3:947F67A7B85439AF2CD5DFED376C51AC7BD67AEE:1:365E9983E466 BA{1:X} map[]}\n  LastValidators:    ValidatorSet{\n      Proposer: Validator{EF243CC0E9B88D0161D24D733BDE9003518CEA27 {PubKeyEd25519{2E0B9301334FCDAB193D514022F81BA09BBEC028685C96602BE9DD0BD4F9E202}} VP:10 A:0}\n      Validators:\n        Validator{EF243CC0E9B88D0161D24D733BDE9003518CEA27 {PubKeyEd25519{2E0B9301334FCDAB193D514022F81BA09BBEC028685C96602BE9DD0BD4F9E202}} VP:10 A:0}\n    }\n}",
    "peer_round_states": []
  }
}
```

After:

```
{
  "jsonrpc": "2.0",
  "id": "",
  "result": {
    "round_state": {
      "Height": 1691,
      "Round": 0,
      "Step": 1,
      "StartTime": "2017-10-09T14:08:09.129491764+04:00",
      "CommitTime": "2017-10-09T14:08:08.129491764+04:00",
      "Validators": {
        "validators": [
          {
            "address": "EF243CC0E9B88D0161D24D733BDE9003518CEA27",
            "pub_key": {
              "type": "ed25519",
              "data": "2E0B9301334FCDAB193D514022F81BA09BBEC028685C96602BE9DD0BD4F9E202"
            },
            "voting_power": 10,
            "accum": 0
          }
        ],
        "proposer": {
          "address": "EF243CC0E9B88D0161D24D733BDE9003518CEA27",
          "pub_key": {
            "type": "ed25519",
            "data": "2E0B9301334FCDAB193D514022F81BA09BBEC028685C96602BE9DD0BD4F9E202"
          },
          "voting_power": 10,
          "accum": 0
        }
      },
      "Proposal": null,
      "ProposalBlock": null,
      "ProposalBlockParts": null,
      "LockedRound": 0,
      "LockedBlock": null,
      "LockedBlockParts": null,
      "Votes": {},
      "CommitRound": -1,
      "LastCommit": {},
      "LastValidators": {
        "validators": [
          {
            "address": "EF243CC0E9B88D0161D24D733BDE9003518CEA27",
            "pub_key": {
              "type": "ed25519",
              "data": "2E0B9301334FCDAB193D514022F81BA09BBEC028685C96602BE9DD0BD4F9E202"
            },
            "voting_power": 10,
            "accum": 0
          }
        ],
        "proposer": {
          "address": "EF243CC0E9B88D0161D24D733BDE9003518CEA27",
          "pub_key": {
            "type": "ed25519",
            "data": "2E0B9301334FCDAB193D514022F81BA09BBEC028685C96602BE9DD0BD4F9E202"
          },
          "voting_power": 10,
          "accum": 0
        }
      }
    },
    "peer_round_states": {
      "75EC8F15D244A421202F9725CD4DE509EE50303670310CF7530EF25E2B7C524B": {
        "Height": 1691,
        "Round": 0,
        "Step": 1,
        "StartTime": "2017-10-09T14:08:08.563251997+04:00",
        "Proposal": false,
        "ProposalBlockPartsHeader": {
          "total": 0,
          "hash": ""
        },
        "ProposalBlockParts": null,
        "ProposalPOLRound": -1,
        "ProposalPOL": null,
        "Prevotes": null,
        "Precommits": null,
        "LastCommitRound": 0,
        "LastCommit": null,
        "CatchupCommitRound": -1,
        "CatchupCommit": null
      }
    }
  }
}
```
2017-10-09 14:09:26 +04:00
a3adac3787 [rpc] do not try to parse params if they were not provided (Refs #708) 2017-10-09 13:30:52 +04:00
6fc82f3824 types/heartbeat: test all Heartbeat functions
Updates https://github.com/tendermint/tendermint/issues/693

* Adjusted Heartbeat.Copy to return nil on
trying to copy a nil value instead of panicking.
* Also documented that WriteSignBytes panics
if the Heartbeat is nil.
2017-10-05 21:24:36 -06:00
bcca27ee20 Merge pull request #718 from tendermint/restore-rpc-lib-readme
restore rpc/lib readme as doc.go (Refs #710) [ci skip]
2017-10-05 22:08:17 -04:00
3702cb7e7c restore rpc/lib readme as doc.go (Refs #710) [ci skip]
I don't want to lose any documentation. Correct me if I am wrong, but we
don't have this docs anywhere else.
2017-10-05 11:44:02 +04:00
49653d3e31 CODEOWNERS file 2017-10-04 23:44:55 -04:00
ddb8430341 Merge pull request #716 from tendermint/unstable
Unstable
2017-10-04 23:43:36 -04:00
91a3cb0f21 makefile: remove megacheck 2017-10-04 23:20:22 -04:00
765c325441 Merge pull request #714 from tendermint/feature/no-block-response
Feature/no block response
2017-10-04 22:27:06 -04:00
659768783f blockchain: fixing reactor tests 2017-10-04 22:26:00 -04:00
e756906a0e Merge pull request #711 from tendermint/imports
get rid of anonymous imports
2017-10-04 22:16:07 -04:00
136b6a7673 rpc/lib: remove dead files, closes #710 2017-10-04 17:45:15 -04:00
068f01368f blockchain/reactor: respondWithNoResponseMessage for missing height
Fixes #514
Replaces #540

If a peer requests a block with a height that we don't have
respond with a bcNoBlockResponseMessage.
However, according to the Tendermint spec, if all nodes are honest
this condition shouldn't occur, so this is a possible hint of an
dishonest node.
2017-10-04 17:27:10 -04:00
f23d47e5d2 upnp: keep a link 2017-10-04 17:19:49 -04:00
09aed7ee89 Merge pull request #707 from tendermint/619-how-to-read-logs
How To Read Logs guide
2017-10-04 16:55:20 -04:00
d56b44f3a5 all: no more anonymous imports 2017-10-04 16:40:45 -04:00
9e4c25761c relative links [ci skip] 2017-10-04 23:33:31 +04:00
54f2cc9709 [docs] add how to read logs guide [ci skip] 2017-10-04 18:35:22 +04:00
31a7e2b3b4 Merge pull request #704 from tendermint/no-empty-docs
document no empty blocks
2017-10-03 23:56:05 -04:00
00ab3daa0c document no empty blocks, closes #605 [ci skip] 2017-10-03 23:55:45 -04:00
bbf0228aa7 Merge pull request #700 from tendermint/695-improve-app-dev-docs
Improve app dev docs
2017-10-03 23:40:21 -04:00
6550199751 [docs] minor fixes from review [ci skip] 2017-10-03 23:39:46 -04:00
10f361fcd0 [docs] use persistent_dummy only when needed [ci skip] 2017-10-04 00:04:45 +04:00
4a0ae17401 [docs] include examples from the persistent_dummy app [ci skip] 2017-10-04 00:04:32 +04:00
8537070575 [docs] restructure sentence [ci skip] 2017-10-04 00:04:22 +04:00
9cbcd4b5e3 Merge pull request #692 from tendermint/unstable
add the unstable changes
2017-10-03 12:47:16 -04:00
4fa4e617b7 docs/ecosystem: add stratumn 2017-10-03 12:47:01 -04:00
2e598a7caf one more fix 2017-10-03 11:26:32 -04:00
031eb23dc8 docs: fix build warnings 2017-10-03 11:23:08 -04:00
edd718c580 Update ecosystem.rst 2017-10-03 11:14:24 -04:00
392a041c2b Merge pull request #699 from tendermint/update-getting-started-docs
remove unnecessary args in abci_query call in getting-started [ci skip]
2017-10-03 10:41:36 -04:00
8727bfc265 remove unnecessary args in abci_query call in getting-started [ci skip]
Since 0.10.0, RPC does not require all args (default values will be used).
2017-10-03 16:21:48 +04:00
84e39203bb readme points to ecosystem doc; add lotion, clean up 2017-10-02 23:46:35 -04:00
97e9802255 fix out of range error in VoteSet.addVote 2017-10-02 23:34:06 -04:00
8c6bd44929 log stack trace on consensus failure 2017-10-02 23:34:06 -04:00
ed5511dc08 glide: update for autofile fix 2017-10-02 23:34:02 -04:00
aa57e89e21 changelog: add genesis amount->power 2017-10-02 14:28:04 -04:00
c2f6ff759b typo 2017-10-02 13:02:45 -04:00
45ff7cdd0c rewrite ws client to expose a callback instead of a channel
callback gives more power to the publisher. plus it is optional
comparing to a channel, which will block the whole client if you won't
read from it.
2017-10-02 13:00:20 -04:00
ce36a0111a rpc: subscribe on reconnection (#689)
* rpc: subscribe on reconnection

* rpc: fix unit tests
2017-10-02 13:00:20 -04:00
b61f5482d4 Fix broken reference to ABCI 2017-10-02 13:00:20 -04:00
40b5defe18 release script [ci skip] 2017-10-02 13:00:20 -04:00
e40d1b36f7 docs: added passchain to the ecosystem.rst in the applications section; 2017-10-02 13:00:20 -04:00
60a2867af2 docs/ecosystem: add ABCI implementations 2017-10-02 12:59:32 -04:00
bfdad916a2 Update ecosystem.rst 2017-10-02 12:59:32 -04:00
498ff803db [README] added passchain to application list;
This adds passchain to the 'applications' part of the toplevel README.md file.
Passchain is a distributed password sharing system built on top of tendermint.
2017-10-02 12:59:32 -04:00
c8789492dc update docker readme [ci skip] 2017-10-02 12:59:32 -04:00
1723836014 update Dockerfile [ci skip] 2017-10-02 12:59:32 -04:00
2d6bc8d7d7 bump up Golang version to 1.9.0 2017-10-02 12:59:32 -04:00
7448c4adde Merge pull request #690 from etherealmachine/patch-1
Fix typo in using-tendermint.rst
2017-10-01 11:03:16 -04:00
a221736eee Fix typo in using-tendermint.rst
configutation -> configuration
2017-09-29 23:18:45 -07:00
382bead548 rpc: fix client websocket timeout (#687) 2017-09-29 13:32:30 +04:00
f9479b34cb sleep time should be greater than readTimeout (5 sec)
otherwise, we're not testing ping/pongs.
see https://github.com/tendermint/tendermint/pull/687#issuecomment-332494735
2017-09-27 15:44:19 +04:00
925696ca65 Merge branch 'p2p-prune-unused-IPRangeCount-funcs' into develop 2017-09-22 21:09:41 -06:00
7682ad9a60 Merge pull request #675 from tendermint/release-v0.11.0
Release v0.11.0
2017-09-22 13:48:52 -04:00
3e92d295e4 glide for tmlibs 0.3.1 2017-09-22 13:25:10 -04:00
661d336dd5 glide 2017-09-22 12:29:53 -04:00
d1a00c684e types: comments 2017-09-22 12:00:37 -04:00
db034e079a version bump 2017-09-22 11:44:57 -04:00
7d983a548b changelog 2017-09-22 11:44:25 -04:00
8311f5c611 abci.Info takes a struct; less merkleeyes 2017-09-22 11:42:40 -04:00
628791e5a5 Merge pull request #665 from tendermint/no-internet
p2p: allow listener with no external connection
2017-09-22 10:16:50 -04:00
df857266b6 update glide 2017-09-22 10:14:05 -04:00
ddb3d8945d p2p: allow listener with no external connection 2017-09-22 10:13:23 -04:00
7f5908b622 Merge pull request #637 from tendermint/feature/hsm
PrivValidator Interface
2017-09-22 00:28:40 -04:00
24f7b9387a more tests 2017-09-22 00:05:39 -04:00
756818f940 fixes from review 2017-09-21 21:44:36 -04:00
2131f8d330 some fixes from review 2017-09-21 17:21:20 -04:00
8ae2ffda89 put funcs back in order to simplify review 2017-09-21 16:59:25 -04:00
75b97a5a65 PrivValidatorFS is like old PrivValidator, for now 2017-09-21 16:46:31 -04:00
7b99039c34 make signBytesHRS a method on LastSignedInfo 2017-09-21 15:54:33 -04:00
3ca7b10ad4 types: more . -> cmn 2017-09-21 15:54:33 -04:00
779c2a22d0 node: NewNode takes DBProvider and GenDocProvider 2017-09-21 15:54:33 -04:00
147a18b34a fix some comments 2017-09-21 15:52:25 -04:00
4382c8d28b fix tests 2017-09-21 15:52:25 -04:00
944ebccfe9 more PrivValidator interface 2017-09-21 15:51:20 -04:00
fd1b0b997a PrivValidator interface 2017-09-21 15:51:20 -04:00
abe912c610 FuncSignerAndApp allows custom signer and abci app 2017-09-21 15:50:43 -04:00
66fcdf7c7a minor fixes 2017-09-21 15:50:43 -04:00
4e13a19339 Add ability to construct new instance of Tendermint core from scratch 2017-09-21 15:50:43 -04:00
7dd3c007c7 Refactor priv_validator
Users can now just pass an object that implements the Signer interface.
2017-09-21 15:50:43 -04:00
0d392a0442 Allow Signer to be generated with priv key
Prior to this change, a custom Signer would have no knowledge of the private
key stored in the configuration file. This changes introduces a generator
function, which creates a Signer based on the private key. This provides an
opportunity for customer Signers to adjust behaviour based on the key
contents. (E.g. imagine key contents are a key label, rather than the key
itself).
2017-09-21 15:50:43 -04:00
7e4a704bd1 Remove reliance on default Signer
This change allows the default privValidator to use a custom Signer
implementation with no reliance on the default Signer implementation.
2017-09-21 15:50:43 -04:00
bf5e956087 Change capitalisation 2017-09-21 15:50:43 -04:00
2ccc3326ec Remove redundant file 2017-09-21 15:50:43 -04:00
83f7d5c95a Setup custom tendermint node
By exporting all of the commands, we allow users to setup their own
tendermint node cli. This enables users to provide a different
pivValidator without the need to fork tendermint.
2017-09-21 15:50:43 -04:00
2c129447fd Example that showcases how to build your own tendermint node
This example shows how a user of the tendermint library can build their
own node and supply it with its own commands. It includes two todos in
order to make it easier for library users to use tendermint.
2017-09-21 15:50:43 -04:00
b50339e8e7 p2p: sw.AddPeer -> sw.addPeer 2017-09-21 15:47:41 -04:00
8ff5b365dd Merge pull request #650 from tendermint/consensus_params
Consensus params
2017-09-21 15:46:57 -04:00
1f0985689d ConsensusParams ptr in GenesisDoc for json 2017-09-21 15:22:58 -04:00
3089bbf2b8 Amount -> Power. Closes #166 2017-09-21 14:59:27 -04:00
5feeb65cf0 dont use pointers for ConsensusParams 2017-09-21 14:59:24 -04:00
715e74186c fixes from review 2017-09-21 14:51:29 -04:00
3a03fe5a15 updated to match adr 005 2017-09-21 14:51:29 -04:00
d343560108 adr: add 005 consensus params 2017-09-21 14:51:29 -04:00
2b6db268cf genesis json tests and mv ConsensusParams to types 2017-09-21 14:51:29 -04:00
14abdd57f3 genDoc.ValidateAndComplete 2017-09-21 14:51:29 -04:00
1f3e4d2d9a move PartSetSize out of the config, into ConsensusParams 2017-09-21 14:51:29 -04:00
29bfcb0a31 minor comments/changes 2017-09-21 14:51:29 -04:00
301845943c Merge pull request #663 from tendermint/readme-update
update readme and other files
2017-09-21 12:36:11 -04:00
b0017c5460 update CHANGELOG [ci skip] 2017-09-21 12:34:37 -04:00
0b61d22652 Merge pull request #664 from tendermint/windows-path
use filepath for windows compatibility
2017-09-21 07:34:20 -04:00
70b95135e6 consensus: use filepath for windows compatibility, closes #595 2017-09-18 17:49:43 -04:00
a3d925ac1d pr fixes 2017-09-18 16:52:00 -04:00
cf9a03f698 docs: organize install a bit better 2017-09-18 16:42:24 -04:00
7f8240dfde Merge pull request #521 from tendermint/json-rpc-patch
updated json response to match spec by @davebryson
2017-09-18 16:37:34 -04:00
f8b152972f return method not found error
if somebody tries to access WS method in non-ws context
2017-09-18 16:36:03 -04:00
95875c55fc ID must be present in both request and response
from the spec:
This member is REQUIRED.
It MUST be the same as the value of the id member in the Request Object.
If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), it MUST be Null.
2017-09-18 16:36:03 -04:00
7fadde0b37 check for request ID after receiving it 2017-09-18 16:36:03 -04:00
e36c79f713 capitalize RpcError 2017-09-18 16:36:03 -04:00
2252071866 update changelog 2017-09-18 16:36:03 -04:00
b700ed8e31 remove check for non-empty message as it should always be present 2017-09-18 16:36:03 -04:00
e1fd587ddd we now omit error if empty 2017-09-18 16:36:03 -04:00
f74de4cb86 include optional data field in error object
```
data
A Primitive or Structured value that contains additional information about the error.
This may be omitted.
The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.).
```
2017-09-18 16:36:02 -04:00
6c1572c9b8 fix invalid memory address or nil pointer dereference 2017-09-18 16:36:02 -04:00
60a1f49a5c updated json response to match spec by @davebryson 2017-09-18 16:35:50 -04:00
740167202f readme & al., update links to docs 2017-09-18 16:23:22 -04:00
e0017c8a97 Merge pull request #654 from tendermint/docs-add-tools
consolidate docs from tools repo
2017-09-18 13:55:37 -04:00
4a78c1bb28 Merge pull request #661 from tendermint/docs-add-ecosystem
docs: add ecosystem from website
2017-09-18 13:55:09 -04:00
1d3f723ccc docs: remove last section from ecosystem 2017-09-18 13:41:12 -04:00
77408b7bde docs: using ABCI-CLI 2017-09-18 13:31:18 -04:00
0cd1bd6d8b Merge pull request #658 from tendermint/organize-docs
docs: organize the directory
2017-09-18 13:08:38 -04:00
881d2ce31e docs: pull from tools' master branch 2017-09-18 12:14:23 -04:00
ad79ead93d docs: add and re-format the ecosystem from website 2017-09-18 11:57:35 -04:00
17a748c796 docs: rename file 2017-09-18 09:39:23 -04:00
583599b19f docs: add software.json from website (ecosystem) 2017-09-18 09:38:22 -04:00
044fe56b43 update changelog 2017-09-16 15:24:30 -04:00
b46da19b74 docs: organize the directory, #656 2017-09-16 15:19:22 -04:00
d635783d07 docs: finish pull from tools 2017-09-16 15:11:10 -04:00
f79e13af38 docs: pull from tools on build 2017-09-16 15:11:10 -04:00
34e6474ad9 docs: organize tm-bench/monitor description 2017-09-16 15:11:10 -04:00
5c96e0c812 docs: add original tm-bench/monitor files 2017-09-16 15:11:10 -04:00
921a2b41f0 docs: add kubes docs to mintnet doc, from tools 2017-09-16 15:11:10 -04:00
a8cec967ac docs: harmonize headers for tools docs 2017-09-16 15:11:10 -04:00
044c500cc0 docs: move images in from tools repo 2017-09-16 15:11:10 -04:00
a917ec9ea2 docs: update index.rst 2017-09-16 15:11:10 -04:00
d4ccc88676 docs: convert from md to rst 2017-09-16 15:11:10 -04:00
12c85c4e60 docs: add original README's from tools repo 2017-09-16 15:11:10 -04:00
90c0267bc1 types: privVal.Sign returns an error 2017-09-16 01:07:04 -04:00
8963bf08aa Merge pull request #657 from tendermint/fix/adr
docs: update and clean up adr
2017-09-15 19:32:58 -04:00
ede4f818fd docs: update and clean up adr 2017-09-15 19:31:37 -04:00
126f63c0a2 Merge pull request #653 from tendermint/improvement/peer_interface
peer interface
2017-09-15 18:43:53 -04:00
aea8629272 peer interface 2017-09-15 18:40:59 -04:00
5138bcb1c7 p2p: delete unused and untested *IPRangeCount functions
Fixes #602

Delete unused and untested functions:
- AddToIPRangeCounts
- CheckIPRangeCounts
2017-09-15 14:03:01 -06:00
cc50dc076a Merge pull request #638 from tendermint/feature/state_tests
Upgrade state_test.go
2017-09-12 14:37:59 -04:00
bf576f0097 state: minor comment fixes 2017-09-12 14:37:32 -04:00
377747b061 Merge pull request #651 from tendermint/doc/testnet
Started expanding "automated deployments" in documentation
2017-09-12 12:41:42 -04:00
870a98ccc3 Last fixes 2017-09-12 17:12:19 +02:00
8eda3efa28 Cleanup lines to fit within 72 characters 2017-09-12 17:08:30 +02:00
e2c3cc9685 docs: give index a Tools section 2017-09-12 10:57:34 -04:00
2a6e71a753 Reformat tests to extract common setup 2017-09-12 16:57:10 +02:00
340d273f83 Started expanding "automated deployments" 2017-09-11 11:34:36 -04:00
54c63726b0 p2p: minor comment fixes 2017-09-06 16:40:21 -04:00
cb80ab2965 Merge remote-tracking branch 'orijtech/p2p-full-test-PeerSet' into develop 2017-09-06 16:40:07 -04:00
c48e772115 p2p: fully test PeerSet, more docs, parallelize PeerSet tests
* Full test PeerSet and check its concurrent guarantees
* Improve the doc for PeerSet.Has and remove unnecessary
defer for a path that sets a variable, make it fast anyways.
* Parallelize PeerSet tests with t.Parallel()
* Document functions in peer_set.go more.
2017-09-06 02:47:31 -06:00
aa78fc14b5 cmd: dont wait for genesis. closes #562 2017-09-06 01:57:21 -04:00
399fb9aa70 consensus: remove support for replay by #HEIGHT. closes #567 2017-09-06 01:53:41 -04:00
ec3c91ac14 Merge pull request #618 from tendermint/historical_validators
Historical validators
2017-09-06 01:46:31 -04:00
fae0603413 more fixes from review 2017-09-06 01:25:57 -04:00
9af837c24d Merge pull request #644 from tendermint/release-v0.10.4
Release v0.10.4
2017-09-05 17:44:48 -04:00
cc2b418f7f p2p: test fix 2017-09-05 17:10:11 -04:00
6ddc30ffc7 Merge branch 'master' into release-v0.10.4 2017-09-05 16:49:57 -04:00
aa7d63f2ff bump version to 0.10.4 2017-09-05 16:46:56 -04:00
50f2ef548c Merge pull request #642 from tendermint/zramsay-patch-1
Delete roadmap.md
2017-09-05 16:26:04 -04:00
b9637f7185 Update changelog and add roadmap 2017-09-05 16:25:02 -04:00
88138c38cf mempool: reactor test 2017-09-05 16:25:02 -04:00
5ad0da1750 Merge pull request #640 from tendermint/read-the-docs
Implement read the docs
2017-09-05 15:37:24 -04:00
9deb647303 fixes from review 2017-09-04 18:29:51 -04:00
b856c45b9c Merge pull request #634 from tendermint/config-p2p
p2p: put maxMsgPacketPayloadSize, recvRate, sendRate in config
2017-09-04 14:16:16 -04:00
f0f1ebe013 rpc: Block and Commit take pointers; return latest on nil 2017-09-03 16:07:37 -04:00
34beff117a state: comments; use wire.BinaryBytes 2017-09-03 16:07:37 -04:00
e2e8746044 rpc: historical validators 2017-09-03 16:07:37 -04:00
78446fd99c state: persist validators 2017-09-03 16:07:37 -04:00
daa258ea6d p2p: put maxMsgPacketPayloadSize, recvRate, sendRate in config
Updates #628
2017-09-01 21:44:15 -04:00
54c85ef8b9 try image 2017-09-01 21:14:26 -04:00
de512c5923 fix 2017-09-01 21:05:12 -04:00
8fd133ff19 docs: pretty-fy 2017-09-01 20:59:27 -04:00
f5ba931115 docs: logo, add readme, fixes 2017-09-01 20:08:22 -04:00
3370e40fe1 Delete roadmap.md
file is out of date & provides no useful information
2017-09-01 19:38:11 -04:00
e509e8f354 docs: clean a bunch of stuff up 2017-08-31 15:30:17 -04:00
aaef2f7c84 docs: link fixes 2017-08-30 22:26:26 -04:00
369aa5854f docs: fix image links 2017-08-30 22:11:21 -04:00
9d12e485e5 docs: rst-ify the intro 2017-08-30 21:43:39 -04:00
dc54fc707e docs: port website's intro for rtd 2017-08-30 21:34:51 -04:00
212a5ebc2e docs: use maxdepth 2 for spec 2017-08-30 21:17:07 -04:00
2d2e769e96 rtd: build fixes 2017-08-30 21:01:05 -04:00
bba35c1486 docs: rpc docs to be slate, see #526, #629 2017-08-30 20:51:48 -04:00
0a902ebf61 docs: organize the specification 2017-08-30 20:47:37 -04:00
70c0f4b936 docs: convert markdown to rst 2017-08-30 17:54:25 -04:00
e19fa59b63 docs: consolidate ADRs 2017-08-30 17:43:39 -04:00
30d351b0c1 Merge pull request #623 from tendermint/fix/no-config-on-version
cmd: don't load config for version command. closes #620
2017-08-30 16:42:58 -04:00
818314c5db docs: add sphinx Makefile & requirements 2017-08-30 16:37:51 -04:00
700e4bb29d docs: test 2017-08-30 15:26:32 -04:00
8ad4a1341f docs: add conf.py 2017-08-30 15:16:39 -04:00
d87acc2d1b cmd: don't load config for version command. closes #620 2017-08-28 15:01:51 -04:00
f2349b1092 Merge pull request #526 from tendermint/feature/rpc-docs
RPC docs
2017-08-25 18:10:21 -04:00
7824b66f5b Merge pull request #548 from tendermint/indexing-proposal
Indexing proposal
2017-08-25 18:02:18 -04:00
83048fb2fe Merge pull request #604 from tendermint/bugfix/ws-io-timeout
Biff up RPC WSClient
2017-08-25 17:59:34 -04:00
9dde1a0bd4 rpc: comments 2017-08-25 17:57:09 -04:00
bc9092d7db Merge pull request #609 from orijtech/parseConfig-doc-update
cmd/tendermint/commands: update ParseConfig doc
2017-08-21 13:55:45 -04:00
56b959b9f9 Merge pull request #611 from tendermint/dont_panic
Dont panic
2017-08-21 13:54:58 -04:00
b3796e0aaa rpc: typo fixes 2017-08-16 15:18:55 -04:00
d24083b257 generate md for Slate 2017-08-16 15:17:08 -04:00
83ec9f773a wrote docs for rpc methods [ci skip]
for all of them except unsafe
2017-08-16 15:17:08 -04:00
9ceccbe9a4 consensus: recover panics in receive routine 2017-08-16 01:01:09 -04:00
35a4912449 dont panic on getVoteBitArray 2017-08-16 00:43:55 -04:00
01e008cedd Merge pull request #607 from tendermint/zramsay-patch-1
fix link from slack to rocket
2017-08-15 12:40:07 -04:00
d8af26e75a cmd/tendermint/commands: update ParseConfig doc 2017-08-12 16:29:11 -06:00
03ddb109ec fix link from slack to rocket 2017-08-11 10:30:04 -04:00
2fd8496bc1 correct handling of pings and pongs
server:
- always has read & write timeouts
- ping handler never blocks the reader (see A)
- sends regular pings to check up on a client

A:
at some point server write buffer can become full, so in order not to
block reads from a client (see
https://github.com/gorilla/websocket/issues/97), server may skip some
pongs. As a result, client may disconnect. But you either have to do
that or block the reader. There is no third way.

client:
- optional read & write timeouts
- optional ping/pong to measure latency
2017-08-10 17:53:49 -04:00
8d7640894d Merge pull request #606 from tendermint/release-v0.10.3
Release v0.10.3
2017-08-10 10:25:48 -04:00
c5a657f540 consensus: test proposal heartbeat 2017-08-10 01:24:23 -04:00
1ea43e513d version bump 2017-08-10 00:14:49 -04:00
c9e11de2a7 consensus: log ProposalHeartbeat msg 2017-08-10 00:12:16 -04:00
f644fc5725 changelog 2017-08-10 00:04:07 -04:00
49278a7f9c Merge pull request #579 from tendermint/feature/sync_status
Add fast-sync status to Status() call
2017-08-09 23:51:25 -04:00
b0728260e9 comments 2017-08-09 23:51:09 -04:00
92ada55e5a make conR.FastSync() thread safe 2017-08-09 14:55:21 -04:00
8840ae6ae2 Merge pull request #597 from zramsay/tendermint-types-links
fix dead tendermint types links in specs
2017-08-08 22:19:10 -04:00
21dab22f17 Merge pull request #599 from zramsay/docs-getting-started
docs fixes throughout
2017-08-08 22:17:44 -04:00
10a849c27e Merge pull request #596 from zramsay/deduplications
Deduplications
2017-08-08 22:16:25 -04:00
236489aecf backlog must always have higher priority 2017-08-08 19:03:48 -04:00
7108c66e3b Merge pull request #584 from tendermint/no-empty-blocks
No empty blocks
2017-08-08 18:10:04 -04:00
797acbe911 ws: small comment 2017-08-08 17:33:17 -04:00
0bf66deb3c fixes from review 2017-08-08 17:09:04 -04:00
d2f3e9faf4 test CreateEmptyBlocksInterval 2017-08-08 16:35:25 -04:00
37f1390473 CreateEmptyBlocks and CreateEmptyBlocksInterval 2017-08-08 16:22:37 -04:00
9b5f21a650 [ws-server] reset readTimeout when we receive something 2017-08-08 16:03:04 -04:00
8267920749 [ws-client] write normal close message 2017-08-08 16:02:37 -04:00
6c85e4be4f change server ping period to be less frequent
no need to ping ws every 10 sec
2017-08-08 13:21:59 -04:00
23a87304cc add a comment for PingPongLatencyTimer [ci skip] 2017-08-08 13:20:58 -04:00
c14b39da5f make RPC server's ping period and pong wait configurable via options 2017-08-07 18:29:55 -04:00
57eee2466b make WSClient thread-safe 2017-08-07 17:56:38 -04:00
5d66d1c28c fixes from review 2017-08-05 13:11:00 -04:00
fb47ca6d35 fixes from review 2017-08-04 21:36:11 -04:00
0013053fae allow to change pong wait and ping period 2017-08-04 10:42:55 -04:00
1abbb11b44 do not exit from reconnectRoutine! 2017-08-03 22:44:18 -04:00
54903adeff add IsReconnecting and IsActive methods 2017-08-03 19:10:15 -04:00
c08618f7e9 expose latency timer on WSClient 2017-08-03 19:10:14 -04:00
d578f7f81e biff up WS client
What's new:
- auto reconnect
- ping/pong
- colored tests
2017-08-03 19:10:14 -04:00
043c6018b4 Merge pull request #591 from tendermint/heartbeat
broadcast proposer heartbeat msg
2017-08-03 14:35:25 -04:00
d0965cca05 forgot heartbeat file 2017-08-03 13:58:17 -04:00
b8ac67e240 some fixes 2017-08-03 13:25:26 -04:00
350d584af8 docs: tons of minor improvements
closes: https://github.com/zramsay/tendermint/issues/3
closes: https://github.com/zramsay/tendermint/issues/5
2017-08-01 15:52:16 -04:00
e3e75376ec fix mintnet-kubernetes link 2017-08-01 14:31:38 -04:00
ab753abfa0 Proposer->Proposal; sign heartbeats 2017-07-29 17:04:28 -04:00
bab7877fa1 route links to godoc rather than deprecated internal implementation, closes https://github.com/zramsay/tendermint/issues/1 2017-07-29 14:33:49 -04:00
10f8101314 fix race 2017-07-29 11:45:07 -04:00
530626dab7 broadcast proposer heartbeat msg 2017-07-29 11:45:02 -04:00
b96d28a42b test progress in higher round 2017-07-28 23:43:30 -04:00
3444bee47f fixes from review; use mempool.TxsAvailable() directly 2017-07-28 23:42:43 -04:00
cf3abe5096 consensus: remove rs from handleMsg 2017-07-28 23:42:19 -04:00
ecdda69fab commit empty blocks when needed to prove app hash 2017-07-28 22:12:11 -04:00
fc3fe9292f fixes from review 2017-07-28 22:12:11 -04:00
d396053872 changelog 2017-07-28 22:11:45 -04:00
e9a2389300 cmd: --consensus.no_empty_blocks 2017-07-28 22:11:45 -04:00
678a9a2e42 TxsAvailable tests 2017-07-28 22:11:45 -04:00
124032e3e9 NoEmptyBlocks config option 2017-07-28 22:11:45 -04:00
4beac54bd9 no empty blocks 2017-07-28 22:11:45 -04:00
39493bcd9a consensus: isProposer func 2017-07-28 22:11:10 -04:00
f96771e753 cleanup CONTRIBUTING.md, part of https://github.com/zramsay/tendermint/issues/7 2017-07-28 16:45:03 -04:00
62f94a7948 deduplicate install, closes https://github.com/zramsay/tendermint/issues/2 2017-07-28 16:34:38 -04:00
e9b7221292 consensus: more comments 2017-07-20 00:59:28 -04:00
5fea1d2675 [.editorconfig] add rule for .proto files [ci skip] 2017-07-19 12:29:10 +03:00
7a492e3612 Merge pull request #549 from tendermint/rpc-server-proposal
RPC server ADR
2017-07-19 10:44:12 +03:00
b893df3348 add rpc server proposal [ci skip] 2017-07-19 10:43:30 +03:00
742b5b705f update link to contributing guidelines in README.md [ci skip] 2017-07-19 10:35:54 +03:00
0153d21f3b Update website links on README.md (#589) [ci skip]
* Update website links on README.md

Changed the blog links to Medium.
Updated Tendermint website links.

* correct link for Tendermint blog [ci skip]
2017-07-19 10:31:49 +03:00
695ad5fe2d Merge pull request #588 from tendermint/comments_cleanup
Comments and cleanup
2017-07-17 13:32:23 -04:00
d8ca0580a8 rpc: move grpc_test from test/ to grpc/ 2017-07-17 12:58:15 -04:00
525fc0ae5b types: block comments 2017-07-17 12:58:15 -04:00
311f18bebf mempool: comments 2017-07-17 12:58:10 -04:00
d49a5166ac scripts/txs: add 0x and randomness 2017-07-17 12:57:30 -04:00
e560dd839f Merge pull request #587 from ramilexe/feature/sync_status
fast sync status
2017-07-17 11:51:44 -04:00
6f8d385dfa fast sync status 2017-07-17 09:44:23 +03:00
086544e367 p2p: sw.peers.List() is empty in sw.OnStart 2017-07-10 20:43:38 -04:00
eed0297ed5 Merge pull request #538 from zramsay/docs-rework
rework docs
2017-07-10 20:32:03 -04:00
b467515719 Merge pull request #576 from tendermint/release-v0.10.2
Release v0.10.2
2017-07-10 16:22:09 -04:00
75df0d91ba comments from review 2017-07-10 13:39:23 -04:00
05c0dfac12 First crack it providing fast-sync endpoint 2017-07-10 19:30:54 +02:00
bcde80fc4f changelog 2017-07-09 18:49:22 -04:00
5f6b996d22 breakup some long lines; add more comments to consensus reactor 2017-07-09 18:38:59 -04:00
74a3a2b56a fix comments 2017-07-09 18:01:25 -04:00
b07d01f102 Add more comments on public functions and extra logging during 'enterPrevote'
Signed-off-by: Adrian Brink <adrian@brink-holdings.com>
2017-07-09 20:35:48 +02:00
eed3959749 version bump 2017-07-09 13:17:01 -04:00
278b2344fe move docs/architechture to docs/hidden 2017-07-08 14:25:15 -04:00
05095954c9 use official golang site for installing 2017-07-08 14:09:56 -04:00
6fef4b080e docs: add docs from website 2017-07-08 14:05:24 -04:00
259111d0e8 address adrian's comment 2017-07-08 14:05:24 -04:00
a707748893 add roadmap.md from site 2017-07-08 14:05:24 -04:00
130ae133c1 fix link in changelog 2017-07-08 14:05:24 -04:00
1d387d7452 contributing: use full version from site 2017-07-08 14:05:24 -04:00
612726d9f6 consensus: better logging 2017-07-07 16:58:16 -04:00
5888ddaab1 consensus: improve logging for conflicting votes 2017-07-07 13:41:50 -04:00
e6cecb9595 p2p: fix test 2017-07-07 13:33:15 -04:00
e36e507463 changelog 2017-07-07 13:30:30 -04:00
3c10f7a122 add p2p flush throttle to config 2017-07-07 13:08:52 -04:00
ca8c34f966 add consensus reactor sleep durations to the config 2017-07-07 12:39:40 -04:00
8355fee16a Merge pull request #563 from tendermint/bugfix/ignore-tmhome-in-tests
Do some cleanup in the test, so it doesn't fail in my shell
2017-07-06 21:48:40 -04:00
7f3c697b6e Merge pull request #559 from tendermint/release-v0.10.1
Release v0.10.1
2017-06-28 11:45:41 -04:00
0d1fa8e884 fixes from review 2017-06-28 11:12:45 -04:00
2e0a4aafa7 Update glide files to proper versions 2017-06-28 13:05:51 +02:00
bfecb5a135 some fixes from review 2017-06-27 16:05:21 -04:00
850da13622 Do some cleanup in the test, so it doesn't fail in my shell 2017-06-27 13:31:32 +02:00
b284d39e05 update changelog 2017-06-26 17:29:39 -04:00
23d8de8962 Merge branch 'develop' into release-v0.10.1 2017-06-26 17:22:57 -04:00
3065059da7 update changelog 2017-06-26 17:20:27 -04:00
e2ed15fa02 rpc: SetWriteDeadline for ws ping. fixes #553 2017-06-26 17:13:39 -04:00
b92814c933 Merge pull request #560 from tendermint/feature/docker-build-automation
Docker build automation
2017-06-26 16:20:05 -04:00
12c084c8c0 ParseGenesisFile -> types.GenesisDocFromFile 2017-06-26 16:16:54 -04:00
e4caf96bcb Calculate validator hash from genesis doc 2017-06-26 17:06:49 +02:00
10982f4d8f Add argument to ParseGenesis to use in light-client 2017-06-26 16:56:51 +02:00
6b38abd57b Cleanup for loop in genesis file load 2017-06-26 13:58:34 +02:00
58105dbd4e Refactored some commands to be more reusable 2017-06-26 13:58:34 +02:00
d0b1bf4e26 [docker] bump golang version to 1.8.3 2017-06-26 12:08:38 +04:00
aa7b3a73f5 [docker] remove dummy app as default [ci skip] 2017-06-26 12:05:50 +04:00
852375be00 [docker] update link to mintnet-k8s [ci skip] 2017-06-26 12:05:50 +04:00
9a80730f38 [docker] fix link to 0.10.0 Dockerfile [ci skip] 2017-06-26 12:05:40 +04:00
24a1b130f9 [docker] build and push scripts [ci skip] 2017-06-26 12:05:34 +04:00
e2fe4a6e9b [docker] bump alpine version [ci skip] 2017-06-26 12:05:23 +04:00
4f5b6528a1 version bump 2017-06-24 22:56:31 -04:00
10828ad063 changelog 2017-06-24 22:55:48 -04:00
b6031d5f4b rpc/lib: set logger on ws conn 2017-06-24 21:55:31 -04:00
5c29d7aba9 rpc/lib: test tcp and unix 2017-06-24 21:27:19 -04:00
bdbefe334d Merge pull request #539 from tendermint/feature/readme_update
Add Code of Conduct
2017-06-24 00:14:08 -04:00
77a3d03385 blockchain: explain isCaughtUp logic 2017-06-23 22:34:38 -04:00
468982ffe4 fixes 2017-06-23 22:12:45 -04:00
2750343de5 Merge branch 'apply-megacheck' into unstable 2017-06-23 21:38:22 -04:00
3c0128a680 undo some megacheck suggestions 2017-06-23 21:36:47 -04:00
4522456d55 Merge remote-tracking branch 'origin/feature/496-deduplicate-tests-in-rpc-tests-and-rpc-client' into unstable 2017-06-23 21:24:09 -04:00
dcc538ff32 Merge remote-tracking branch 'origin/feature/506-tracing-logger' into unstable 2017-06-23 21:16:02 -04:00
a22f7358cd Merge pull request #552 from tendermint/feature/551-default-to-tcp
httpDialer accepts no prefix or http:// as tcp://
2017-06-22 23:49:50 -04:00
aac85a14f0 httpDialer accepts no prefix or http:// as tcp:// 2017-06-22 20:56:57 +02:00
a676b2aa10 add indexing proposal [ci skip] 2017-06-21 15:07:45 +04:00
df934c1707 Add Code of Conduct 2017-06-19 15:46:15 +02:00
eaec0c8ea5 deduplicate tests in rpc/test and rpc/client (Refs #496) 2017-06-16 17:14:27 +04:00
4f0f50c62d Merge pull request #535 from tendermint/bugfix/fix-invalid-logger-keys
Fix invalid logger keys
2017-06-14 13:20:10 +04:00
b4ece65726 standardize key for errors (should be "err") 2017-06-14 12:50:49 +04:00
562dd67e16 fix invalid keys (space is prohibited by logfmt encoder) 2017-06-14 12:50:01 +04:00
da646a8986 Merge pull request #534 from hxzqlh/master
logger key doesn't support blank space
2017-06-14 12:38:13 +04:00
b9b2782c3c logger key doesn't support space 2017-06-14 14:41:36 +08:00
f1c087116f Merge pull request #518 from tendermint/feature/504-move-log-level-parsing-to-cli-package
move log level parsing to tmlibs/cli package (Refs #504)
2017-06-12 19:47:22 +04:00
9dcf130d67 update tmlibs (Refs #504) 2017-06-12 19:25:34 +04:00
ed7183936d move log level parsing to tmlibs/cli package (Refs #504) 2017-06-12 19:08:39 +04:00
e5342f4054 docker: update for 0.10.0 [ci skip]" 2017-06-03 21:37:59 -04:00
2e173d4abf Merge branch 'master' into develop 2017-06-03 00:13:14 -04:00
ca632c9e90 Merge pull request #527 from tendermint/release-v0.10.0
Release v0.10.0
2017-06-02 23:59:46 -04:00
c94a92b30d update changelog and readme 2017-06-02 23:33:03 -04:00
84fea82043 dist: dont mkdir in container 2017-06-02 23:20:02 -04:00
d608e2b7ad bump version to 0.10.0 2017-06-02 23:19:30 -04:00
d19d8e7914 update readme and changelog 2017-06-02 23:18:10 -04:00
9c3eee0b00 Makefile: add megacheck & some additional fixes 2017-05-30 13:35:34 -04:00
bf5181d9ca address PR comments 2017-05-30 13:27:08 -04:00
989cb6dd2e update Dockerfile [ci skip] 2017-05-30 16:33:48 +03:00
cf31f8d06f core: apply megacheck vet tool (unused, gosimple, staticcheck) 2017-05-29 23:11:40 -04:00
c7cd62b449 Merge branch 'master' into develop 2017-05-29 10:53:33 -04:00
2b5b017253 Merge pull request #516 from tendermint/release-v0.10.0-rc2
fixes to changelog, config, default logging
2017-05-29 08:58:20 -04:00
630c6ef7b5 bump version 2017-05-29 02:47:09 -04:00
ee88272216 enable unsafe rpc routes in tests via flag 2017-05-26 14:20:23 -04:00
bd7ec18c19 fix tests 2017-05-26 12:17:32 -04:00
42626d9e16 [types] overwrite pubkey/addr in LoadPrivValidator. closes #500 2017-05-25 13:40:13 -04:00
fc6611b2d9 [config] RPCConfig 2017-05-24 13:56:12 -04:00
4f27752468 [rpc] dont enable unsafe by default; limit /blockchain_info to 20 blocks 2017-05-24 11:31:31 -04:00
9bc1790320 tracing logger (Refs #506)
DEPENDS ON https://github.com/tendermint/tmlibs/pull/21
2017-05-24 14:28:25 +02:00
3fbe286e5a small fixes to changelog, config, default logging 2017-05-22 08:16:25 -04:00
aa22bd8464 Merge pull request #511 from spring1843/fix-typos
Fix commonly misspelled words
2017-05-21 13:24:35 +02:00
cf686d4f83 Fix commonly misspelled words 2017-05-20 21:43:00 -07:00
267f134d44 Merge pull request #508 from tendermint/release-v0.10.0-rc1
Release v0.10.0 rc1
2017-05-18 13:45:17 +02:00
d4fa98de68 update version for rc1 2017-05-18 07:20:37 -04:00
790e04ed3e add link to list of breaking funcs/methods 2017-05-18 12:32:34 +02:00
772306cac8 update changelog and glide 2017-05-18 06:16:08 -04:00
30a19fc899 [consensus] Info->Debug for is a validator log msg 2017-05-18 11:26:15 +02:00
6a30a902c9 [types] more []byte->data.Bytes and some %X->%v 2017-05-17 01:08:41 +02:00
883b71ca70 update CHANGELOG 2017-05-17 00:27:03 +02:00
11b5d11e9e Merge pull request #505 from tendermint/dont-hash-accum
[types] dont hash validator.Accum
2017-05-17 00:19:28 +02:00
6d83c60c40 [types] dont hash validator.Accum 2017-05-17 00:16:38 +02:00
cc2b430e68 update glide and changelog 2017-05-17 00:12:56 +02:00
9d7d8075d1 Merge remote-tracking branch 'origin/update-for-new-abci-api' into develop 2017-05-16 23:58:48 +02:00
fe87623674 Merge pull request #501 from tendermint/feature/493-per-module-log-levels
Feature/493 per module log levels
2017-05-16 23:33:21 +02:00
91dc87e7c4 update for a new ABCI API 2017-05-16 19:06:35 +02:00
fb0df75de0 changes per Frey comments (Refs #493) 2017-05-16 15:16:50 +02:00
e1792c1ea5 fix tx string format take 2 2017-05-16 14:12:48 +02:00
d5113377e2 fix tx string format 2017-05-16 14:01:52 +02:00
eb9ca23250 log whether node is a validator in each round 2017-05-16 14:01:52 +02:00
05a8204508 per module log levels (Refs #493) 2017-05-16 13:57:28 +02:00
e041b2eee6 Merge pull request #502 from tendermint/adrianbrink-patch-1
Update README.md
2017-05-16 10:13:31 +02:00
0a4ab7e38f Update README.md 2017-05-16 09:50:52 +02:00
c4ad0f76e6 Merge pull request #494 from tendermint/json-naming
Clean up json output
2017-05-15 19:03:25 +02:00
0f1edcd57d Merge pull request #497 from tendermint/feature/color-code-different-consensus-instances
Color code different consensus instances in consensus tests
2017-05-15 19:02:02 +02:00
118d565534 Merge pull request #472 from tendermint/string_reprs
Add Tx String representation. Got the ok from Anton.
2017-05-15 09:49:40 +02:00
1dfb95f719 [consensus] color code different consensus instances in consensus tests
(Refs #492)
2017-05-15 09:35:29 +02:00
33f807d9a1 Merge pull request #489 from tendermint/feature/adrian-#469
Use ld flags to set git hash instead of "revision_file"
2017-05-14 21:52:29 +02:00
926fb83e33 Re-added comment 2017-05-14 19:10:58 +02:00
2b324b7eb9 RPC returns pretty formated json 2017-05-14 19:06:34 +02:00
157ec8af2d Add json tags to validator set 2017-05-14 19:06:33 +02:00
f14f167297 Merge pull request #491 from tendermint/feature/new-logging
New logging
2017-05-14 00:45:21 +02:00
4fe67652ff move SetLogger down 2017-05-14 00:24:58 +02:00
c5bccc5474 set missing logger on switch
```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x882cec]

goroutine 328 [running]:
github.com/tendermint/tendermint/p2p.(*Switch).DialPeerWithAddress(0xc42000a500, 0xc4202088d0, 0xc420403500, 0x0, 0x0, 0x0)
        /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch.go:324 +0x2fc
github.com/tendermint/tendermint/p2p.(*PEXReactor).ensurePeers.func1(0xc4201663f0, 0xc4202088d0)
        /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/pex_reactor.go:280 +0x3e
created by github.com/tendermint/tendermint/p2p.(*PEXReactor).ensurePeers
        /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/pex_reactor.go:284 +0x5d4
```
2017-05-13 17:05:44 +02:00
f8fdbe3dbc changes as per Bucky's review 2017-05-13 16:22:51 +02:00
c9cd8de9c6 set logger 2017-05-13 10:25:00 +02:00
3e1343dc6b has as a base16 string 2017-05-13 10:24:59 +02:00
bc4e6566e7 [p2p] refactor upnp to use new logger 2017-05-13 10:24:59 +02:00
16509ac3db p2p: fix race by peer.Start() before peers.Add() 2017-05-13 10:24:59 +02:00
f803544195 new logging 2017-05-13 10:24:58 +02:00
8eb07800b3 Merge pull request #473 from tendermint/logging-arch-proposal
Logging architecture proposal
2017-05-12 20:40:28 +02:00
538b325150 update arch proposal [ci skip] [circleci skip] 2017-05-12 20:32:57 +02:00
cd3c3c3bad Modify makefile 2017-05-09 11:39:46 +02:00
8c91014cd8 Add git commit hash to version. 2017-05-09 11:37:59 +02:00
6312eb91be Change "make build" to set GitCommit variable
As described above.
2017-05-06 12:37:48 +02:00
d2ae7e164a Make testify a testImport for consistency 2017-05-05 19:46:32 +02:00
627a686f90 Merge pull request #487 from tendermint/fixp2ptests
One silly tests passes on osx, fails on linux...
2017-05-05 12:53:39 -04:00
57527f9f67 One silly tests passes on osx, fails on linux... comment out so i can develop 2017-05-05 18:48:39 +02:00
14d0d395f2 Merge pull request #484 from tendermint/config
Config
2017-05-05 12:46:39 -04:00
edd7263f06 fixes from review 2017-05-05 12:25:53 -04:00
2a9e89b34f Add basic tests on config, mainly to raise test coverage 2017-05-05 15:50:23 +02:00
dd1f5a2268 Test config parsing in root command 2017-05-05 15:30:39 +02:00
8a0466d81d config: pex_reactor -> pex 2017-05-05 02:04:24 -04:00
fb9d3842e4 test: p2p.seeds and p2p.pex 2017-05-05 01:28:43 -04:00
8c3823545d update glide 2017-05-05 00:51:03 -04:00
75989342b0 fixes from rebase 2017-05-04 23:03:42 -04:00
46151720f8 fix tests 2017-05-04 22:46:41 -04:00
9109b20852 SetRoot 2017-05-04 22:46:41 -04:00
6b059e0063 Accept relative paths in all configs, TODO: must SetRoot 2017-05-04 22:46:40 -04:00
92dee7ea3c Commands compile (mostly) with new config reading 2017-05-04 22:46:40 -04:00
604bf03f3a Pulled out all config structs (except p2p.PeerConfig) into config package 2017-05-04 22:46:40 -04:00
f217f2b2c5 cleanup run_node flags 2017-05-04 22:46:13 -04:00
92bafa7ecd consensus: fix tests 2017-05-04 22:46:13 -04:00
6afee8f117 rpc: fix tests 2017-05-04 22:45:13 -04:00
1ef7c1d25b cmd: fixes for new config 2017-05-04 22:43:55 -04:00
7db7bbe464 node: ConfigFromViper 2017-05-04 22:43:55 -04:00
57151d6043 p2p: use cmn instead of . 2017-05-04 22:43:55 -04:00
5d660e073a remove viper from p2p 2017-05-04 22:43:55 -04:00
4982cb4d1f fix tests for state and mempool 2017-05-04 22:43:55 -04:00
24ce90fc72 fix up config defaults 2017-05-04 22:43:55 -04:00
75b6c5215f fewer structs. remove viper from consensus 2017-05-04 22:43:55 -04:00
d8fb226ec4 new config 2017-05-04 22:43:55 -04:00
95c74b2ccd remove some more viper 2017-05-04 22:43:55 -04:00
f0e7f0acf8 remove viper from rpc except test 2017-05-04 22:43:55 -04:00
1fcc9dc654 remove viper from proxy 2017-05-04 22:39:22 -04:00
7c0f51e24b remove viper from mempool 2017-05-04 22:39:22 -04:00
29c0e6e4f4 remove viper from blockchain and state 2017-05-04 22:39:21 -04:00
56a1a2d917 remove logrotate.config 2017-05-04 22:39:03 -04:00
4871e64b03 update docker README [ci skip] [circleci skip] 2017-05-04 13:36:27 +04:00
809e0e8c59 update Dockerfile [ci skip] [circleci skip] 2017-05-04 13:32:46 +04:00
4305d054d6 Merge pull request #465 from tendermint/bytes
RPC Serialization Overhaul
2017-05-03 14:37:21 -04:00
9860c8fee1 rpc: cleanup some comments [ci skip] 2017-05-03 14:33:07 -04:00
7ebf011fcd Fixed rpctypes.Request creation to new format 2017-05-03 16:58:21 +02:00
4a1b714ca4 All tests pass without go-wire json ptr madness 2017-05-03 16:45:00 +02:00
4c1d41c12e Test json rpc parsing 2017-05-03 16:26:18 +02:00
6ba799132c json.RawMessage in RPCRequest to defer parsing 2017-05-03 16:13:58 +02:00
e5d8fcd198 Merge pull request #474 from faddat/patch-4
Fix Mintnet Kubernetes link
2017-05-03 13:56:45 +02:00
f31d6ffb8c Fix Mintnet kubernetes url 2017-05-03 13:55:42 +02:00
2608b95b4b Merge pull request #463 from tendermint/feature/adrian-initchain
InitChain message gets send at genesis.
2017-05-01 12:00:29 -04:00
2bf8c40cff Add extra memory to virtual machine and add coverage report to gitignore. 2017-05-01 17:29:44 +02:00
b5ab74fd38 Update README.md
updated mintnet to mintnet-kubernetes
2017-05-01 15:50:11 +07:00
556fbf0c4c logging arch proposal [ci skip] [circleci skip] 2017-05-01 11:58:43 +04:00
4c7a2be06a Add Tx String representation 2017-04-30 16:06:49 -07:00
6dbcfb32d2 comment on copied wire file 2017-04-28 23:22:54 -04:00
efeadcc0f4 some cleanup from review 2017-04-28 23:18:38 -04:00
297772e009 Merge pull request #467 from tendermint/nowire
Nowire
2017-04-28 22:58:39 -04:00
aa9e673ed7 test: jq .result[1] -> jq .result 2017-04-28 22:31:30 -04:00
4e781961e9 remove TMResult. ::drinks champagne:: 2017-04-28 22:26:23 -04:00
884060eb9b rpc/lib: no Result wrapper 2017-04-28 22:04:14 -04:00
07e59e63f9 TMEventDataInner 2017-04-28 17:57:06 -04:00
ac28b12fa8 add readReflectJSON from wire 2017-04-28 17:56:44 -04:00
257f45b768 ebuchman: added some demos on how to parse unknown types 2017-04-28 22:01:46 +02:00
acfbea6d49 rpc: decode args without wire 2017-04-28 14:36:38 -04:00
6c60c07f16 BROKEN: attempt to replace go-wire.JSON with json.Unmarshall in rpc 2017-04-28 16:24:06 +02:00
bff8402fe8 Fix json for TMResult to not include "TMResultInner" 2017-04-28 15:26:06 +02:00
f6f1f1992c Prepare rpc responses for go-data compatibility, still use go-wire 2017-04-28 14:46:04 +02:00
194f345470 Use non-standard port so tests don't die when I am running basecoin 2017-04-28 14:45:34 +02:00
2bf7e9c968 update glide 2017-04-27 19:58:12 -04:00
c930f43cbe rpc: fix tests 2017-04-27 19:56:14 -04:00
a518d08839 rpc: response types use Result instead of pb Response 2017-04-27 19:34:25 -04:00
cdf650fba9 rpc: repsonse types use data.Bytes 2017-04-27 19:06:07 -04:00
bdb34f9f4e types: []byte -> data.Bytes 2017-04-27 19:01:18 -04:00
0be3480729 consensus: comment about test_data [ci skip] 2017-04-27 18:34:57 -04:00
495283e2d4 fix replay tests and update test wals for InitChain 2017-04-27 18:30:43 -04:00
842609ddcb Send InitChain message from ABCI to Core on Genesis
InitChain is send from the ABCI to the Core node when the ABCI
app has no blocks stored.
2017-04-27 20:22:11 +02:00
1310c72647 version bump and changelog 2017-04-26 20:06:45 -04:00
cc6dde96c1 rpc -> rpc/lib and rpc/tendermint -> rpc 2017-04-26 19:57:33 -04:00
cc7b2d26e5 Merge branch 'master' into develop 2017-04-26 19:21:06 -04:00
1781a52147 Merge pull request #459 from tendermint/http_codes
rpc: use HTTP error codes
2017-04-26 19:05:43 -04:00
0ba449c8ba Merge pull request #455 from tendermint/unstable
Unstable
2017-04-26 19:04:52 -04:00
9851265d4f rpc: use HTTP error codes 2017-04-25 23:09:47 -04:00
098646c5ff test: test_libs all use Makefile 2017-04-25 18:35:22 -04:00
0e5cd6dc2f Merge pull request #442 from tendermint/viper
go-config -> viper, commands: Run -> RunE
2017-04-25 17:59:17 -04:00
2fcb2b9232 remove unsafe_set_config 2017-04-25 17:58:26 -04:00
fcf78a5da7 cleanup go-config/viper and some unnamed imports 2017-04-25 14:54:56 -04:00
72c4be35e8 tiny fix 2017-04-25 13:44:13 -04:00
5d0c2a1414 commands: Run -> RunE 2017-04-25 13:44:13 -04:00
7bb638e3b8 fix test_integrations error 2017-04-25 13:44:13 -04:00
7448753257 fixing tests 2017-04-25 13:43:57 -04:00
6e662337ff dont export resetPrivValidator 2017-04-25 13:43:57 -04:00
270b68a893 glide lock updates 2017-04-25 13:43:22 -04:00
cefb2bede0 adding viper
int

int
2017-04-25 13:42:22 -04:00
47852122d0 changed reset commands 2017-04-25 13:34:46 -04:00
00055fa2e8 Merge pull request #456 from tendermint/repo-merge
Repo merge
2017-04-25 13:13:32 -04:00
bd93f76950 Improve rpc to properly format any alias for []byte in URIClient 2017-04-25 17:17:51 +02:00
803b1f2115 Improve client test cases 2017-04-25 16:49:01 +02:00
3cdd2daf08 fix tests 2017-04-21 18:44:37 -04:00
4e0afc55e6 glide update 2017-04-21 18:35:48 -04:00
e160318eef glide update 2017-04-21 18:21:59 -04:00
56c60fba23 go-p2p -> tendermint/p2p 2017-04-21 18:19:41 -04:00
9e82d132ce go-rpc -> tendermint/rpc 2017-04-21 18:19:29 -04:00
a70c95b79e tmlibs/common/test -> tmlibs/test 2017-04-21 18:18:22 -04:00
d5b524e309 go-merkle -> merkleeyes/iavl and tmlibs/merkle 2017-04-21 18:16:05 -04:00
e6fe6b5b76 go-data -> go-wire/data 2017-04-21 18:13:25 -04:00
d1926bcad1 use tmlibs 2017-04-21 18:12:54 -04:00
fa451fc55c tendermint/rpc -> tendermint/rpc/tendermint 2017-04-21 18:10:41 -04:00
5da9b3a803 postmerge 2017-04-21 18:09:47 -04:00
93c58d0b24 remove glide and license from rpc and p2p 2017-04-21 18:08:25 -04:00
23a6a6f8fc move into p2p package 2017-04-21 18:07:52 -04:00
63f546497b Merge remote-tracking branch 'p2p/develop' into repo-merge 2017-04-21 18:06:57 -04:00
c55d83281a move into rpc package 2017-04-21 18:05:39 -04:00
35f1db09a9 Merge remote-tracking branch 'rpc/develop' into repo-merge 2017-04-21 18:04:42 -04:00
34965f610d crypto Wrap/Unwrap 2017-04-21 18:02:25 -04:00
eaeb547938 use tmlibs 2017-04-21 17:53:22 -04:00
15d5b2ac49 use tmlibs 2017-04-21 17:51:11 -04:00
992b11c450 premerge2: rpc -> rpc/tendermint 2017-04-21 17:39:56 -04:00
0017fb7ffe premerge 2017-04-21 17:38:40 -04:00
3240ce21b8 update glide 2017-04-21 17:28:13 -04:00
543eea4f4e update deps to unstable 2017-04-21 16:56:10 -04:00
6d223d5526 Update to latest go-crypto 2017-04-21 16:55:58 -04:00
3d9ca32e95 Update all config for p2p integration tests 2017-04-21 16:55:38 -04:00
90abc61c56 Improve go-data json support in rpc 2017-04-21 16:55:37 -04:00
6a0217688f Ensure private validator addresses are hex 2017-04-21 16:51:17 -04:00
b798169c6e Update go-crypto to read/write properly with go-wire in wal files 2017-04-21 16:51:17 -04:00
7e56aad51a [consensus/test_data/build.sh] install tendermint if absent 2017-04-21 16:51:17 -04:00
e325ffc681 Lots of updates to use new go-crypto / json style 2017-04-21 16:51:17 -04:00
516e78ea54 Fix types to use updated go-crypto 2017-04-21 16:50:27 -04:00
2c8df0ee6b Merge pull request #17 from tendermint/develop
v0.7.0
2017-04-21 13:08:14 -04:00
e8f33a4784 Merge pull request #25 from tendermint/develop
v0.5.0
2017-04-21 13:06:44 -04:00
58ccefa407 update changelog 2017-04-21 13:06:26 -04:00
559613689d Merge pull request #18 from tendermint/bugfix/fix-backward-compatibility-for-ws
fix backward compatibility for WS
2017-04-21 12:20:34 -04:00
a01cff9ce6 jsonParamsToArgsRPC func 2017-04-21 12:18:21 -04:00
d6fd0c4ca0 fix backward compatibility for WS 2017-04-21 18:30:22 +03:00
17124989a9 Merge pull request #10 from tendermint/pex-reactor-fixes-#9
Pex reactor fixes #9
2017-04-20 17:32:38 -04:00
75bad132fc msgCountByPeer is a CMap 2017-04-20 17:29:43 -04:00
391c738959 update comment about outbound peers and addrbook 2017-04-20 12:21:45 -04:00
8655e2456e it is non-deterministic (could fail sometimes) 2017-04-20 13:37:06 +04:00
17ec70fc09 revert 2710873 2017-04-20 13:36:40 +04:00
9ce71013df revert e448199 2017-04-20 13:36:40 +04:00
5ab8ca0868 fix race 2017-04-20 13:36:40 +04:00
4c0d1d3ad2 return wg to addrbook 2017-04-20 13:36:39 +04:00
0277e52bd5 fix merge 2017-04-20 13:36:39 +04:00
cf18bf2966 add public RemoveAddress API
after discussion with @ebuchman (https://github.com/tendermint/go-p2p/pull/10#discussion_r96471729)
2017-04-20 13:36:39 +04:00
324293f4cb note on preventing abuse [ci skip] 2017-04-20 13:36:39 +04:00
52d9cf080e make GoLint happy 2017-04-20 13:36:39 +04:00
590efc1040 call saveToFile OnStop
This is better than waiting because while we wait, anything could happen
(crash, timeout of the code who's using addrbook, ...). If we save
immediately, we have much greater chances of success.
2017-04-20 13:36:38 +04:00
5eeaffd38e do not create file, just temp dir 2017-04-20 13:36:38 +04:00
07e7b98c70 improve ensurePeers routine
optimizations:

- if we move peer to the old bucket as soon as connected and pick only
  from new group, we can skip alreadyConnected check
2017-04-20 13:36:38 +04:00
873d34157d prevent abuse from peers 2017-04-20 13:36:38 +04:00
47df1fb7d4 test PEXReactor#Receive 2017-04-20 13:36:38 +04:00
1a59b6a3b4 replace repeate timer with simple ticker
no need for repeate timer here (no need for goroutine safety)
2017-04-20 13:36:38 +04:00
0109f1e524 test ensurePeers goroutine 2017-04-20 13:36:37 +04:00
37d5a2cf3e implement RemovePeer for PEXReactor 2017-04-20 13:36:37 +04:00
3af7c67757 add Dockerfile 2017-04-20 13:36:37 +04:00
26f661a5dd prefer short names 2017-04-20 13:36:37 +04:00
057cfb30f1 remove unused error 2017-04-20 13:36:37 +04:00
1a42f946dc version bump 2017-04-19 00:05:18 -04:00
e05052b079 update glide 2017-04-19 00:01:55 -04:00
7d5b62b61f CHANGELOG and version bump 2017-04-18 23:58:24 -04:00
e6b7e66bbe Merge pull request #23 from tendermint/more-tests
More tests
2017-04-18 20:26:54 -04:00
2ac69176e1 add a comment for MConnection#CanSend
also add a note to TestMConnectionSend
2017-04-18 12:11:48 +04:00
fbedb426ce tests for NetAddress 2017-04-14 16:37:07 +04:00
6dc113aa80 [netaddress] panic only when normal run 2017-04-14 14:56:02 +04:00
ebe23f1379 refactor MConnection#sendBytes 2017-04-14 14:21:58 +04:00
06d219db8e test peer with no auth enc 2017-04-14 12:43:28 +04:00
1d01f6af98 2 kinds of peers: outbound and inbound 2017-04-13 12:36:16 +04:00
715b8c629f use the peer struct to simulate remote peer 2017-04-13 12:09:43 +04:00
a63e1bb2dc fix possible panic 2017-04-13 12:08:57 +04:00
5965578c56 [fuzz] only one way to set config variables 2017-04-13 11:55:14 +04:00
4671c44b2d Merge pull request #13 from tendermint/allow-for-multiple-restarts
[WSClient] allow for multiple restarts
2017-04-12 19:32:24 -04:00
052c2c1575 Merge pull request #11 from tendermint/feature/refactor-tests
WSClient failing to echo bytes
2017-04-12 19:32:14 -04:00
4b30cb3083 test: check err on cmd.Wait 2017-04-12 19:30:05 -04:00
8c38543357 fix error msg 2017-04-12 18:15:51 -04:00
c3295f4878 RPCRequest.Params can be map[string]interface{} or []interface{} 2017-04-12 13:42:19 -04:00
7dcc3dbcd1 test peer 2017-04-12 16:55:17 +04:00
c39e001a95 Merge pull request #22 from tendermint/persistent
fix closing conn
2017-04-11 13:40:06 -04:00
8067cdb5f2 fix closing conn 2017-04-11 12:42:11 -04:00
9d18cbe74e Remove race condition between read go-routine and stop 2017-04-11 13:38:15 +02:00
ebd3929c0d Merge pull request #18 from tendermint/13-reconnect-to-seeds
persistent peers (Refs 13)
2017-04-10 16:21:02 -04:00
9a1a6c56b4 dont expose makePersistent 2017-04-10 16:05:00 -04:00
b6f744c732 fix AddPeerWithConnection 2017-04-10 16:03:14 -04:00
a9bb6734e7 SetDeadline for authEnc. Stop peer if Add fails 2017-04-10 16:02:01 -04:00
8bb3a2e1d7 persistent peers (Refs #13) 2017-04-10 22:47:05 +04:00
f88d56b2f8 add glide 2017-04-10 22:47:04 +04:00
5b0489cdb4 use plain struct instead of go-config 2017-04-10 22:46:49 +04:00
b8a939a894 test non persistent mconnection 2017-04-10 22:46:48 +04:00
2b02843453 remove unused const 2017-04-10 22:46:48 +04:00
5be72672fe use golang time datatype instead of time units in name 2017-04-10 22:46:48 +04:00
549d3bd09a tests for MConnection 2017-04-10 22:46:48 +04:00
868017cf1a import go-common as cmn 2017-04-10 22:46:48 +04:00
ba5382b70e open result&error channels on start 2017-03-28 14:17:40 +04:00
b0d2032488 use BaseService.OnReset method to recreate channels 2017-03-28 14:01:22 +04:00
a416c37ebd Merge pull request #12 from tendermint/close-ws-connection
close ws connection on Stop
2017-03-27 20:50:18 +04:00
d6587be7bc [WSClient] allow for multiple restarts
needed for 3044f66ba9
See https://github.com/tendermint/tools/issues/6
2017-03-21 22:08:08 +04:00
afc39febed close ws connection on Stop 2017-03-21 22:02:25 +04:00
b54b9b4ecc update url to network monitor [ci skip] [circleci skip] 2017-03-13 14:25:57 +04:00
5d19a008ce add Call method to WSClient, which does proper encoding of params 2017-03-10 15:33:45 +04:00
3233c9c003 WSClient failed to "echo_bytes"
Error:
```
Expected nil, but got: encoding/hex: invalid byte: U+0078 'x'
```
2017-03-10 14:56:04 +04:00
c88257b038 rename rpc function status to echo
echo means we're returning the input, which is exactly what this
function does.
2017-03-10 12:57:14 +04:00
0874c72819 refactor tests 2017-03-10 12:52:40 +04:00
d66ebbd904 use testify package 2017-03-10 12:03:16 +04:00
1a3573bf17 Merge pull request #10 from tendermint/feature/4-rename-http-clients
rename ClientURI -> URIClient, ClientJSONRPC -> JSONRPCClient
2017-03-10 10:42:22 +04:00
e6c083f589 rename ClientURI -> URIClient, ClientJSONRPC -> JSONRPCClient (Refs #4) 2017-03-10 10:41:10 +04:00
759060f47e Merge pull request #9 from tendermint/feature/8-http-interface-and-1-key-value-params-json-rpc
support key-value params in JSONRPC
2017-03-10 10:29:00 +04:00
715f78e26a Properly encode json.RawMessage 2017-03-10 10:20:38 +04:00
db69845ded introduce errors pkg 2017-03-09 19:01:37 +04:00
ff90224ba8 fix "Expected map but got type string" error
Error from tendermint:

```
panic: Expected map but got type string [recovered]
        panic: Expected map but got type string

goroutine 82 [running]:
testing.tRunner.func1(0xc420464000)
        /usr/local/go/src/testing/testing.go:622 +0x29d
panic(0xa1fda0, 0xc4201eecd0)
        /usr/local/go/src/runtime/panic.go:489 +0x2cf
github.com/tendermint/tendermint/rpc/test.waitForEvent(0xc420464000, 0xc420064000, 0xae6fae, 0x8, 0xae6f01, 0xc2e998, 0xc2e9a0)
        /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/test/helpers.go:179 +0x53a
github.com/tendermint/tendermint/rpc/test.TestWSNewBlock(0xc420464000)
        /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/test/client_test.go:190 +0x12e
testing.tRunner(0xc420464000, 0xc2e9a8)
        /usr/local/go/src/testing/testing.go:657 +0x96
created by testing.(*T).Run
        /usr/local/go/src/testing/testing.go:697 +0x2ca
```
2017-03-09 19:01:32 +04:00
720b74d89e read from ErrorsCh also 2017-03-09 17:44:00 +04:00
05e1a22d5b encode params before sending in JSONRPC 2017-03-09 13:46:48 +04:00
cf11e6ba65 add CHANGELOG 2017-03-09 12:43:24 +04:00
1ddb60b6e7 refactor jsonParamsToArgs
Suggested in https://github.com/tendermint/go-rpc/pull/9#discussion_r105098390
2017-03-09 12:23:21 +04:00
fed84f875c fix jsonParamsToArgsWS index error
Error from tendermint:
```
panic: runtime error: index out of range

goroutine 82 [running]:
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-rpc/server.jsonParamsToArgsWS(0xc4200960e0, 0xc42024d4a0, 0xc420215380, 0x3, 0x0, 0x0, 0xc420215383, 0x9, 0xc42024d4a0, 0xf1ecc0, ...)
        /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-rpc/server/handlers.go:184 +0x654
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-rpc/server.(*wsConnection).readRoutine(0xc4201fd0e0)
        /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-rpc/server/handlers.go:496 +0x3a9
created by github.com/tendermint/tendermint/vendor/github.com/tendermint/go-rpc/server.(*wsConnection).OnStart
        /home/vagrant/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-rpc/server/handlers.go:377 +0x45
```
2017-03-08 17:55:08 +04:00
1842e03315 revert using local import
this breaks the client's code (e.g. tendermint)
2017-03-08 17:33:46 +04:00
d033cd54b8 add editorconfig 2017-03-08 17:17:42 +04:00
2dc6ab3896 use golang default if an arg is missing (Refs #7) 2017-03-08 17:16:01 +04:00
6d66cc68ed make sure we are using correct server
also remove it afterwards
2017-03-08 16:55:15 +04:00
51d760f29f use local import for testing 2017-03-08 16:23:38 +04:00
22ba8bdef8 fix Call method signature in HTTPClient interface 2017-03-08 10:26:13 +04:00
d43e3db978 fix circleci 2017-03-07 19:28:00 +04:00
26ccb4c94a remove private call methods
Q: what was the reason to create them?
2017-03-07 19:27:52 +04:00
c128957723 "must remove file for test to run again" - no way I am doing this by hands, too lazy :) 2017-03-07 19:27:38 +04:00
66867bf949 remove "rpc" prefix from package imports 2017-03-07 19:27:32 +04:00
e1d5873bdf support key-value params in JSONRPC (Refs #1)
More changes:

- remove Client interface (reason: empty)
- introduce HTTPClient interface, which can be used for both ClientURI
  and ClientJSONRPC clients (so our users don't have to create their own) (Refs #8)
- rename integration tests script to `integration_test.sh`
- do not update deps on `get_deps`
2017-03-07 19:27:27 +04:00
b03facd828 add Dockerfile 2017-03-07 18:34:13 +04:00
97a5ed2d1a Merge pull request #16 from tendermint/develop
v0.4.0
2017-03-06 03:11:04 -05:00
53d777a2d5 CHANGELOG.md 2017-03-06 01:30:41 -05:00
beb3eda438 fix addrbook start/stop 2017-03-05 22:59:18 -05:00
c94bc2bc2b DialSeeds takes an addrbook 2017-03-05 21:57:07 -05:00
56eebb95ee Merge pull request #12 from tendermint/bugfix/pex-issues-335
PEX issues #335
2017-03-04 23:19:51 -05:00
88b5c724f2 remove public addr book funcs from pex 2017-03-04 22:55:42 -05:00
65b1756978 expose 2 API functions for tendermint#node/node.go 2017-03-04 22:44:25 -05:00
108beae7a8 more tests for AddrBook 2017-03-04 22:44:25 -05:00
2773410de4 prevent nil addr
Error:

```
Error: runtime error: invalid memoryaddress or nil pointer dereference\nStack:
goroutine 549 [running]:\nruntime/debug.Stack(0x0, 0x0,
0x0)\n\t/usr/local/go/src/runtime/debug/stack.go:24
+0x80\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection)._recover(0xc821723b00)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:173
+0x53\npanic(0xbe1500, 0xc820012080)\n\t/usr/local/go/src/runtime/panic.go:443
+0x4e9\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*NetAddress).Valid(0x0,
0x0)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/netaddress.go:125
+0x1c\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*NetAddress).Routable(0x0,
0xc8217bb740)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/netaddress.go:117
+0x25\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*AddrBook).addAddress(0xc820108380,
0x0,
0xc821739590)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/addrbook.go:524
+0x45\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*AddrBook).AddAddress(0xc820108380,
0x0,
0xc821739590)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/addrbook.go:160
+0x286\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*PEXReactor).Receive(0xc82000be60,
0xc820149f00, 0xc8218163f0, 0xc82184e000, 0x5b,
0x1000)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/pex_reactor.go:109
+0x457\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.newPeer.func1(0xc82011d500,
0xc82184e000, 0x5b,
0x1000)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/peer.go:58
+0x202\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection).recvRoutine(0xc821723b00)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:439
+0x1177\ncreated by
github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection).OnStart\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:138
+0x1a1\n
```
2017-03-04 22:40:48 -05:00
e7656873c1 public save API 2017-03-04 22:40:48 -05:00
332f7056f7 start/stop the book with reactor
Refs https://github.com/tendermint/tendermint/issues/335
2017-03-04 22:40:48 -05:00
17e6ae813f Merge pull request #15 from tendermint/seedsfix
Seedsfix
2017-03-03 17:33:23 -05:00
dab31d0166 version bump to 0.4.0 2017-03-03 17:30:38 -05:00
0e7baf027b some dial seeds fixes 2017-03-03 16:42:10 -05:00
26275ba66c dial seeds error handling 2017-03-03 16:42:10 -05:00
fcea0cda21 Merge pull request #6 from tendermint/develop
v0.6.0
2017-01-12 22:02:40 -05:00
6177eb8398 love you circley 2017-01-12 22:01:20 -05:00
ac443fa61f run tests from bash script 2017-01-12 21:59:02 -05:00
08f2b5bc84 get deps for testing 2017-01-12 21:51:34 -05:00
de56442660 Merge branch 'master' into develop 2017-01-12 21:40:43 -05:00
3d98f675f3 Merge pull request #11 from tendermint/develop
Develop
2017-01-12 21:39:57 -05:00
67c9086b74 optional panic on AddPeer err 2017-01-12 21:09:24 -05:00
e47722ecb2 Connect2Switches: panic on err 2017-01-12 20:49:48 -05:00
2b750ea49f Make Connect2Switches blocking 2017-01-12 20:49:48 -05:00
58e42397f8 close conns on filter; fix order in MakeConnectedSwitch 2017-01-12 20:49:48 -05:00
bd353e004a QuitService->BaseService 2017-01-12 20:49:48 -05:00
94fed25975 fix test 2017-01-12 10:22:23 -05:00
0eb278ad3b version bump 0.6.0 2017-01-12 00:13:20 -05:00
b494cc5219 Merge pull request #5 from mappum/develop
Fix hex string handling
2017-01-12 00:12:11 -05:00
4d7aa62a10 Added test for unexpected hex string type HTTP args 2017-01-07 20:40:45 -08:00
86506cd4f8 Handle quoted and hex string type HTTP args for both 'string' and '[]byte' type function args 2017-01-07 20:40:29 -08:00
af1212897c Exit early in bash tests 2017-01-07 14:00:27 -08:00
34a806578a Handle hex strings and quoted strings in HTTP params
Use 0x-prefixed hex strings in client

server: Decode hex string args

Encode all string args as 0x<hex> without trying to encode as JSON

Added tests for special string arguments

Fix server handling quoted string args

Added string arg handling test cases to bash test script
2017-01-07 13:59:33 -08:00
eab2baa363 use go-flowrate instead of flowcontrol 2016-12-04 18:20:37 -08:00
2cee364692 addrbook: toggle strict routability 2016-11-30 22:57:21 -05:00
161e36fd56 QuitService->BaseService 2016-10-28 12:04:58 -07:00
e6e3853dc7 Merge pull request #3 from tendermint/develop
use EventSwitch interface; less logging
2016-10-20 21:31:26 -04:00
1eb390680d Merge pull request #8 from tendermint/develop
update MakeConnectedSwitches
2016-10-10 14:48:58 -04:00
855255d73e use EventSwitch interface; less logging 2016-10-10 03:22:34 -04:00
153ac88672 update MakeConnectedSwitches 2016-09-14 00:57:53 -04:00
f508f3f20b Merge pull request #6 from tendermint/develop
filter conn by addr/pubkey. closes #3
2016-09-09 19:45:12 -04:00
642901d5aa filter conn by addr/pubkey. closes #3 2016-08-25 13:46:43 -04:00
479510be0e support full urls (with eg tcp:// prefix) 2016-08-10 01:13:13 -04:00
dea910cd3e Makefile: go test --race 2016-07-22 01:15:52 -04:00
39ee59c26e server: return result with error 2016-07-22 01:13:16 -04:00
929cf433b9 fix chDesc race 2016-06-26 00:34:34 -04:00
711d2541f5 MakeConnectedSwitches function 2016-06-26 00:34:23 -04:00
a8ac819139 link issue from readme 2016-06-23 20:40:16 -04:00
a44e0e0f4b add test example 2016-06-23 20:37:35 -04:00
0c70a4636a add better docs to readme 2016-06-23 20:33:04 -04:00
7ea86f6506 fix test race and update readme 2016-06-21 15:19:56 -04:00
7376a72dd7 circle badge 2016-06-21 14:40:24 -04:00
981c6868ad fix race conditions in tests 2016-06-21 14:35:29 -04:00
5bd7692323 version bump 2016-05-12 00:10:46 -04:00
6684a18730 fix test 2016-05-12 00:08:41 -04:00
0dc6ebc325 configurable fuzz conn 2016-05-12 00:00:52 -04:00
ffbd6d8782 drop the p2p_ 2016-05-11 23:47:51 -04:00
7d997ca8e6 No global config 2016-05-08 14:59:27 -07:00
1d9e89812a Remove go-alert dependency 2016-05-08 14:58:28 -07:00
e8538d606a add blank client interface 2016-05-04 10:39:43 -04:00
78c9d526c3 change some log.Info to log.Debug 2016-03-29 11:37:51 -07:00
4baf007fb8 Merge pull request #2 from tendermint/develop
make some params configurable
2016-03-27 20:44:10 -07:00
69c7ae5e3f version bump 2016-03-17 05:05:02 -04:00
114d90bec8 don't reallocate on recvMsgPacket 2016-03-17 05:05:02 -04:00
10619248c6 Use go-crypto CRand* 2016-03-13 09:42:36 -07:00
389e4b8b69 config: toggle authenticated encryption 2016-03-10 19:07:01 -05:00
1bc871162d Conform to new go-config behavior; ApplyConfig not needed 2016-03-06 12:33:07 -08:00
f28f791fff make some params configurable 2016-03-06 12:24:01 -08:00
7f6aad20fb Add note on nondeterminism of Broadcast 2016-03-04 22:04:05 -08:00
1410693eae support unix domain websockets 2016-02-19 02:05:24 +00:00
74130008f7 deduplicate dialFunc 2016-02-19 00:20:20 +00:00
6607232a5d add support for unix sockets 2016-02-18 22:45:55 +00:00
1370f89864 Fix bug in receiveEventsRoutine error handling 2016-02-08 02:20:34 -08:00
8b7969d6ea Add comments about goroutine-safety 2016-02-08 00:58:12 -08:00
45f57198cc client: wsc.String() 2016-02-03 02:01:28 -05:00
fbc5ac8052 print method in client log 2016-01-21 23:03:39 -05:00
b9eec7e438 version bump 2016-01-20 13:07:57 -05:00
9bc75eaf24 move DialSeeds in from tendermint/tendermint/node 2016-01-20 11:32:23 -05:00
0380e404bd Conform to go-wire version 0.6.0 2016-01-17 21:30:06 -08:00
14735d5eb5 RawMessage fix 2016-01-13 22:16:56 -05:00
91c734d02e client: ResultsCh chan json.RawMessage, ErrorsCh 2016-01-13 21:21:16 -05:00
aff561d8c3 RPCResponse.Result is json.RawMessage 2016-01-13 18:37:35 -05:00
0bcae125c2 use comma separated string for arg names 2016-01-12 18:29:31 -05:00
3d59e13dd8 move from tendermint/tendermint 2016-01-12 16:50:06 -05:00
c52524a215 Initial commit 2016-01-12 15:26:00 -05:00
1f2c1d0760 Fix prioritization logic; Add Status() 2016-01-03 06:20:18 -08:00
3abc18d7ba Add MConnection.Status() 2016-01-02 20:53:10 -08:00
0c9b9fe8bb Change license to Apache2.0 2015-12-23 14:08:39 -08:00
44d8e62689 Confirm to go-wire new TypeByte behavior 2015-12-21 12:55:52 -08:00
8b308c1c08 Tweak send/recv rates for performance test 2015-12-09 13:53:50 -08:00
4347b91b89 Remove wrong comment 2015-12-05 09:48:08 -08:00
432a37857d Add RemoteAddr and ListenAddr to NodeInfo; Refactor IPRange logic 2015-12-05 09:44:03 -08:00
c37e25e76b Conform to go-common WriteFile*(path, mode) 2015-12-04 00:02:44 -08:00
1c628a97ad Conform to go-wire 1.0 2015-11-10 12:29:43 -08:00
abc3a2cc3c initial commit 2015-10-25 18:21:51 -07:00
500 changed files with 45625 additions and 9178 deletions

201
.circleci/config.yml Normal file
View File

@ -0,0 +1,201 @@
version: 2
defaults: &defaults
working_directory: /go/src/github.com/tendermint/tendermint
docker:
- image: circleci/golang:1.10.0
environment:
GOBIN: /tmp/workspace/bin
jobs:
setup_dependencies:
<<: *defaults
steps:
- run: mkdir -p /tmp/workspace/bin
- run: mkdir -p /tmp/workspace/profiles
- checkout
- restore_cache:
keys:
- v1-pkg-cache
- run:
name: tools
command: |
export PATH="$GOBIN:$PATH"
make get_tools
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- run:
name: binaries
command: |
export PATH="$GOBIN:$PATH"
make install
- persist_to_workspace:
root: /tmp/workspace
paths:
- bin
- profiles
- save_cache:
key: v1-pkg-cache
paths:
- /go/pkg
- save_cache:
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
paths:
- /go/src/github.com/tendermint/tendermint
setup_abci:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v1-pkg-cache
- restore_cache:
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: Checkout abci
command: |
commit=$(bash scripts/dep_utils/parse.sh abci)
go get -v -u -d github.com/tendermint/abci/...
cd /go/src/github.com/tendermint/abci
git checkout "$commit"
- run:
working_directory: /go/src/github.com/tendermint/abci
name: Install abci
command: |
set -ex
export PATH="$GOBIN:$PATH"
make get_tools
make get_vendor_deps
make install
- run: ls -lah /tmp/workspace/bin
- persist_to_workspace:
root: /tmp/workspace
paths:
- "bin/abci*"
lint:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v1-pkg-cache
- restore_cache:
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: metalinter
command: |
set -ex
export PATH="$GOBIN:$PATH"
make metalinter
test_apps:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v1-pkg-cache
- restore_cache:
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
- run: sudo apt-get update && sudo apt-get install -y --no-install-recommends bsdmainutils
- run:
name: Run tests
command: bash test/app/test.sh
test_cover:
<<: *defaults
parallelism: 4
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v1-pkg-cache
- restore_cache:
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: Run tests
command: |
for pkg in $(go list github.com/tendermint/tendermint/... | grep -v /vendor/ | circleci tests split --split-by=timings); do
id=$(basename "$pkg")
go test -timeout 5m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg"
done
- persist_to_workspace:
root: /tmp/workspace
paths:
- "profiles/*"
test_persistence:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v1-pkg-cache
- restore_cache:
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: Run tests
command: bash test/persist/test_failure_indices.sh
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/circleci/p2p.sh
upload_coverage:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: gather
command: |
set -ex
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 <(curl -s https://codecov.io/bash) -f coverage.txt
workflows:
version: 2
test-suite:
jobs:
- setup_dependencies
- setup_abci:
requires:
- setup_dependencies
- lint:
requires:
- setup_dependencies
- test_apps:
requires:
- setup_abci
- test_cover:
requires:
- setup_dependencies
- test_persistence:
requires:
- setup_abci
- test_p2p
- upload_coverage:
requires:
- test_cover

View File

@ -1,21 +0,0 @@
#
# This codecov.yml is the default configuration for
# all repositories on Codecov. You may adjust the settings
# below in your own codecov.yml in your repository.
#
coverage:
precision: 2
round: down
range: 70...100
status:
# Learn more at https://codecov.io/docs#yaml_default_commit_status
project:
default:
threshold: 1% # allow this much decrease on project
changes: false
comment:
layout: "header, diff"
behavior: default # update if exists else create new

View File

@ -8,8 +8,9 @@ end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[Makefile]
[*.{sh,Makefile}]
indent_style = tab
[*.sh]
indent_style = tab
[*.proto]
indent_style = space
indent_size = 2

4
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,4 @@
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
# Everything goes through Bucky and Anton. For now.
* @ebuchman @melekes

View File

@ -37,5 +37,8 @@ in a case of bug.
**How to reproduce it** (as minimally and precisely as possible):
**Logs (you can paste a part showing an error or attach the whole file)**:
**`/dump_consensus_state` output for consensus bugs**
**Anything else do we need to know**:

6
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,6 @@
<!-- Thanks for filing a PR! Before hitting the button, please check the following items.-->
* [ ] Updated all relevant documentation in docs
* [ ] Updated all code comments where relevant
* [ ] Wrote tests
* [ ] Updated CHANGELOG.md

11
.gitignore vendored
View File

@ -14,3 +14,14 @@ vendor
test/p2p/data/
test/logs
.glide
coverage.txt
docs/_build
docs/tools
docs/abci-spec.rst
*.log
scripts/wal2json/wal2json
scripts/cutWALUntil/cutWALUntil
.idea/
*.iml

View File

@ -1,5 +1,423 @@
# Changelog
## Roadmap
BREAKING CHANGES:
- Better support for injecting randomness
- Upgrade consensus for more real-time use of evidence
FEATURES:
- Use the chain as its own CA for nodes and validators
- Tooling to run multiple blockchains/apps, possibly in a single process
- State syncing (without transaction replay)
- Add authentication and rate-limitting to the RPC
IMPROVEMENTS:
- Improve subtleties around mempool caching and logic
- Consensus optimizations:
- cache block parts for faster agreement after round changes
- propagate block parts rarest first
- Better testing of the consensus state machine (ie. use a DSL)
- Auto compiled serialization/deserialization code instead of go-wire reflection
BUG FIXES:
- Graceful handling/recovery for apps that have non-determinism or fail to halt
- Graceful handling/recovery for violations of safety, or liveness
## 0.19.0 (April 13th, 2018)
BREAKING:
- [cmd] improved `testnet` command; now it can fill in `persistent_peers` for you in the config file and much more (see `tendermint testnet --help` for details)
- [cmd] `show_node_id` now returns an error if there is no node key
- [rpc]: changed the output format for the `/status` endpoint (see https://godoc.org/github.com/tendermint/tendermint/rpc/core#Status)
Upgrade from go-wire to go-amino. This is a sweeping change that breaks everything that is
serialized to disk or over the network.
See github.com/tendermint/go-amino for details on the new format.
See `scripts/wire2amino.go` for a tool to upgrade
genesis/priv_validator/node_key JSON files.
FEATURES:
- [cmd] added `gen_node_key` command
## 0.18.0 (April 6th, 2018)
BREAKING:
- [types] Merkle tree uses different encoding for varints (see tmlibs v0.8.0)
- [types] ValidtorSet.GetByAddress returns -1 if no validator found
- [p2p] require all addresses come with an ID no matter what
- [rpc] Listening address must contain tcp:// or unix:// prefix
FEATURES:
- [rpc] StartHTTPAndTLSServer (not used yet)
- [rpc] Include validator's voting power in `/status`
- [rpc] `/tx` and `/tx_search` responses now include the transaction hash
- [rpc] Include peer NodeIDs in `/net_info`
IMPROVEMENTS:
- [config] trim whitespace from elements of lists (like `persistent_peers`)
- [rpc] `/tx_search` results are sorted by height
- [p2p] do not try to connect to ourselves (ok, maybe only once)
- [p2p] seeds respond with a bias towards good peers
BUG FIXES:
- [rpc] fix subscribing using an abci.ResponseDeliverTx tag
- [rpc] fix tx_indexers matchRange
- [rpc] fix unsubscribing (see tmlibs v0.8.0)
## 0.17.1 (March 27th, 2018)
BUG FIXES:
- [types] Actually support `app_state` in genesis as `AppStateJSON`
## 0.17.0 (March 27th, 2018)
BREAKING:
- [types] WriteSignBytes -> SignBytes
IMPROVEMENTS:
- [all] renamed `dummy` (`persistent_dummy`) to `kvstore` (`persistent_kvstore`) (name "dummy" is deprecated and will not work in the next breaking release)
- [docs] note on determinism (docs/determinism.rst)
- [genesis] `app_options` field is deprecated. please rename it to `app_state` in your genesis file(s). `app_options` will not work in the next breaking release
- [p2p] dial seeds directly without potential peers
- [p2p] exponential backoff for addrs in the address book
- [p2p] mark peer as good if it contributed enough votes or block parts
- [p2p] stop peer if it sends incorrect data, msg to unknown channel, msg we did not expect
- [p2p] when `auth_enc` is true, all dialed peers must have a node ID in their address
- [spec] various improvements
- switched from glide to dep internally for package management
- [wire] prep work for upgrading to new go-wire (which is now called go-amino)
FEATURES:
- [config] exposed `auth_enc` flag to enable/disable encryption
- [config] added the `--p2p.private_peer_ids` flag and `PrivatePeerIDs` config variable (see config for description)
- [rpc] added `/health` endpoint, which returns empty result for now
- [types/priv_validator] new format and socket client, allowing for remote signing
BUG FIXES:
- [consensus] fix liveness bug by introducing ValidBlock mechanism
## 0.16.0 (February 20th, 2018)
BREAKING CHANGES:
- [config] use $TMHOME/config for all config and json files
- [p2p] old `--p2p.seeds` is now `--p2p.persistent_peers` (persistent peers to which TM will always connect to)
- [p2p] now `--p2p.seeds` only used for getting addresses (if addrbook is empty; not persistent)
- [p2p] NodeInfo: remove RemoteAddr and add Channels
- we must have at least one overlapping channel with peer
- we only send msgs for channels the peer advertised
- [p2p/conn] pong timeout
- [lite] comment out IAVL related code
FEATURES:
- [p2p] added new `/dial_peers&persistent=_` **unsafe** endpoint
- [p2p] persistent node key in `$THMHOME/config/node_key.json`
- [p2p] introduce peer ID and authenticate peers by ID using addresses like `ID@IP:PORT`
- [p2p/pex] new seed mode crawls the network and serves as a seed.
- [config] MempoolConfig.CacheSize
- [config] P2P.SeedMode (`--p2p.seed_mode`)
IMPROVEMENT:
- [p2p/pex] stricter rules in the PEX reactor for better handling of abuse
- [p2p] various improvements to code structure including subpackages for `pex` and `conn`
- [docs] new spec!
- [all] speed up the tests!
BUG FIX:
- [blockchain] StopPeerForError on timeout
- [consensus] StopPeerForError on a bad Maj23 message
- [state] flush mempool conn before calling commit
- [types] fix priv val signing things that only differ by timestamp
- [mempool] fix memory leak causing zombie peers
- [p2p/conn] fix potential deadlock
## 0.15.0 (December 29, 2017)
BREAKING CHANGES:
- [p2p] enable the Peer Exchange reactor by default
- [types] add Timestamp field to Proposal/Vote
- [types] add new fields to Header: TotalTxs, ConsensusParamsHash, LastResultsHash, EvidenceHash
- [types] add Evidence to Block
- [types] simplify ValidateBasic
- [state] updates to support changes to the header
- [state] Enforce <1/3 of validator set can change at a time
FEATURES:
- [state] Send indices of absent validators and addresses of byzantine validators in BeginBlock
- [state] Historical ConsensusParams and ABCIResponses
- [docs] Specification for the base Tendermint data structures.
- [evidence] New evidence reactor for gossiping and managing evidence
- [rpc] `/block_results?height=X` returns the DeliverTx results for a given height.
IMPROVEMENTS:
- [consensus] Better handling of corrupt WAL file
BUG FIXES:
- [lite] fix race
- [state] validate block.Header.ValidatorsHash
- [p2p] allow seed addresses to be prefixed with eg. `tcp://`
- [p2p] use consistent key to refer to peers so we dont try to connect to existing peers
- [cmd] fix `tendermint init` to ignore files that are there and generate files that aren't.
## 0.14.0 (December 11, 2017)
BREAKING CHANGES:
- consensus/wal: removed separator
- rpc/client: changed Subscribe/Unsubscribe/UnsubscribeAll funcs signatures to be identical to event bus.
FEATURES:
- new `tendermint lite` command (and `lite/proxy` pkg) for running a light-client RPC proxy.
NOTE it is currently insecure and its APIs are not yet covered by semver
IMPROVEMENTS:
- rpc/client: can act as event bus subscriber (See https://github.com/tendermint/tendermint/issues/945).
- p2p: use exponential backoff from seconds to hours when attempting to reconnect to persistent peer
- config: moniker defaults to the machine's hostname instead of "anonymous"
BUG FIXES:
- p2p: no longer exit if one of the seed addresses is incorrect
## 0.13.0 (December 6, 2017)
BREAKING CHANGES:
- abci: update to v0.8 using gogo/protobuf; includes tx tags, vote info in RequestBeginBlock, data.Bytes everywhere, use int64, etc.
- types: block heights are now `int64` everywhere
- types & node: EventSwitch and EventCache have been replaced by EventBus and EventBuffer; event types have been overhauled
- node: EventSwitch methods now refer to EventBus
- rpc/lib/types: RPCResponse is no longer a pointer; WSRPCConnection interface has been modified
- rpc/client: WaitForOneEvent takes an EventsClient instead of types.EventSwitch
- rpc/client: Add/RemoveListenerForEvent are now Subscribe/Unsubscribe
- rpc/core/types: ResultABCIQuery wraps an abci.ResponseQuery
- rpc: `/subscribe` and `/unsubscribe` take `query` arg instead of `event`
- rpc: `/status` returns the LatestBlockTime in human readable form instead of in nanoseconds
- mempool: cached transactions return an error instead of an ABCI response with BadNonce
FEATURES:
- rpc: new `/unsubscribe_all` WebSocket RPC endpoint
- rpc: new `/tx_search` endpoint for filtering transactions by more complex queries
- p2p/trust: new trust metric for tracking peers. See ADR-006
- config: TxIndexConfig allows to set what DeliverTx tags to index
IMPROVEMENTS:
- New asynchronous events system using `tmlibs/pubsub`
- logging: Various small improvements
- consensus: Graceful shutdown when app crashes
- tests: Fix various non-deterministic errors
- p2p: more defensive programming
BUG FIXES:
- consensus: fix panic where prs.ProposalBlockParts is not initialized
- p2p: fix panic on bad channel
## 0.12.1 (November 27, 2017)
BUG FIXES:
- upgrade tmlibs dependency to enable Windows builds for Tendermint
## 0.12.0 (October 27, 2017)
BREAKING CHANGES:
- rpc/client: websocket ResultsCh and ErrorsCh unified in ResponsesCh.
- rpc/client: ABCIQuery no longer takes `prove`
- state: remove GenesisDoc from state.
- consensus: new binary WAL format provides efficiency and uses checksums to detect corruption
- use scripts/wal2json to convert to json for debugging
FEATURES:
- new `certifiers` pkg contains the tendermint light-client library (name subject to change)!
- rpc: `/genesis` includes the `app_options` .
- rpc: `/abci_query` takes an additional `height` parameter to support historical queries.
- rpc/client: new ABCIQueryWithOptions supports options like `trusted` (set false to get a proof) and `height` to query a historical height.
IMPROVEMENTS:
- rpc: `/genesis` result includes `app_options`
- rpc/lib/client: add jitter to reconnects.
- rpc/lib/types: `RPCError` satisfies the `error` interface.
BUG FIXES:
- rpc/client: fix ws deadlock after stopping
- blockchain: fix panic on AddBlock when peer is nil
- mempool: fix sending on TxsAvailable when a tx has been invalidated
- consensus: dont run WAL catchup if we fast synced
## 0.11.1 (October 10, 2017)
IMPROVEMENTS:
- blockchain/reactor: respondWithNoResponseMessage for missing height
BUG FIXES:
- rpc: fixed client WebSocket timeout
- rpc: client now resubscribes on reconnection
- rpc: fix panics on missing params
- rpc: fix `/dump_consensus_state` to have normal json output (NOTE: technically breaking, but worth a bug fix label)
- types: fixed out of range error in VoteSet.addVote
- consensus: fix wal autofile via https://github.com/tendermint/tmlibs/blob/master/CHANGELOG.md#032-october-2-2017
## 0.11.0 (September 22, 2017)
BREAKING:
- genesis file: validator `amount` is now `power`
- abci: Info, BeginBlock, InitChain all take structs
- rpc: various changes to match JSONRPC spec (http://www.jsonrpc.org/specification), including breaking ones:
- requests that previously returned HTTP code 4XX now return 200 with an error code in the JSONRPC.
- `rpctypes.RPCResponse` uses new `RPCError` type instead of `string`.
- cmd: if there is no genesis, exit immediately instead of waiting around for one to show.
- types: `Signer.Sign` returns an error.
- state: every validator set change is persisted to disk, which required some changes to the `State` structure.
- p2p: new `p2p.Peer` interface used for all reactor methods (instead of `*p2p.Peer` struct).
FEATURES:
- rpc: `/validators?height=X` allows querying of validators at previous heights.
- rpc: Leaving the `height` param empty for `/block`, `/validators`, and `/commit` will return the value for the latest height.
IMPROVEMENTS:
- docs: Moved all docs from the website and tools repo in, converted to `.rst`, and cleaned up for presentation on `tendermint.readthedocs.io`
BUG FIXES:
- fix WAL openning issue on Windows
## 0.10.4 (September 5, 2017)
IMPROVEMENTS:
- docs: Added Slate docs to each rpc function (see rpc/core)
- docs: Ported all website docs to Read The Docs
- config: expose some p2p params to tweak performance: RecvRate, SendRate, and MaxMsgPacketPayloadSize
- rpc: Upgrade the websocket client and server, including improved auto reconnect, and proper ping/pong
BUG FIXES:
- consensus: fix panic on getVoteBitArray
- consensus: hang instead of panicking on byzantine consensus failures
- cmd: dont load config for version command
## 0.10.3 (August 10, 2017)
FEATURES:
- control over empty block production:
- new flag, `--consensus.create_empty_blocks`; when set to false, blocks are only created when there are txs or when the AppHash changes.
- new config option, `consensus.create_empty_blocks_interval`; an empty block is created after this many seconds.
- in normal operation, `create_empty_blocks = true` and `create_empty_blocks_interval = 0`, so blocks are being created all the time (as in all previous versions of tendermint). The number of empty blocks can be reduced by increasing `create_empty_blocks_interval` or by setting `create_empty_blocks = false`.
- new `TxsAvailable()` method added to Mempool that returns a channel which fires when txs are available.
- new heartbeat message added to consensus reactor to notify peers that a node is waiting for txs before entering propose step.
- rpc: Add `syncing` field to response returned by `/status`. Is `true` while in fast-sync mode.
IMPROVEMENTS:
- various improvements to documentation and code comments
BUG FIXES:
- mempool: pass height into constructor so it doesn't always start at 0
## 0.10.2 (July 10, 2017)
FEATURES:
- Enable lower latency block commits by adding consensus reactor sleep durations and p2p flush throttle timeout to the config
IMPROVEMENTS:
- More detailed logging in the consensus reactor and state machine
- More in-code documentation for many exposed functions, especially in consensus/reactor.go and p2p/switch.go
- Improved readability for some function definitions and code blocks with long lines
## 0.10.1 (June 28, 2017)
FEATURES:
- Use `--trace` to get stack traces for logged errors
- types: GenesisDoc.ValidatorHash returns the hash of the genesis validator set
- types: GenesisDocFromFile parses a GenesiDoc from a JSON file
IMPROVEMENTS:
- Add a Code of Conduct
- Variety of improvements as suggested by `megacheck` tool
- rpc: deduplicate tests between rpc/client and rpc/tests
- rpc: addresses without a protocol prefix default to `tcp://`. `http://` is also accepted as an alias for `tcp://`
- cmd: commands are more easily reuseable from other tools
- DOCKER: automate build/push
BUG FIXES:
- Fix log statements using keys with spaces (logger does not currently support spaces)
- rpc: set logger on websocket connection
- rpc: fix ws connection stability by setting write deadline on pings
## 0.10.0 (June 2, 2017)
Includes major updates to configuration, logging, and json serialization.
Also includes the Grand Repo-Merge of 2017.
BREAKING CHANGES:
- Config and Flags:
- The `config` map is replaced with a [`Config` struct](https://github.com/tendermint/tendermint/blob/master/config/config.go#L11),
containing substructs: `BaseConfig`, `P2PConfig`, `MempoolConfig`, `ConsensusConfig`, `RPCConfig`
- This affects the following flags:
- `--seeds` is now `--p2p.seeds`
- `--node_laddr` is now `--p2p.laddr`
- `--pex` is now `--p2p.pex`
- `--skip_upnp` is now `--p2p.skip_upnp`
- `--rpc_laddr` is now `--rpc.laddr`
- `--grpc_laddr` is now `--rpc.grpc_laddr`
- Any configuration option now within a substract must come under that heading in the `config.toml`, for instance:
```
[p2p]
laddr="tcp://1.2.3.4:46656"
[consensus]
timeout_propose=1000
```
- Use viper and `DefaultConfig() / TestConfig()` functions to handle defaults, and remove `config/tendermint` and `config/tendermint_test`
- Change some function and method signatures to
- Change some [function and method signatures](https://gist.github.com/ebuchman/640d5fc6c2605f73497992fe107ebe0b) accomodate new config
- Logger
- Replace static `log15` logger with a simple interface, and provide a new implementation using `go-kit`.
See our new [logging library](https://github.com/tendermint/tmlibs/log) and [blog post](https://tendermint.com/blog/abstracting-the-logger-interface-in-go) for more details
- Levels `warn` and `notice` are removed (you may need to change them in your `config.toml`!)
- Change some [function and method signatures](https://gist.github.com/ebuchman/640d5fc6c2605f73497992fe107ebe0b) to accept a logger
- JSON serialization:
- Replace `[TypeByte, Xxx]` with `{"type": "some-type", "data": Xxx}` in RPC and all `.json` files by using `go-wire/data`. For instance, a public key is now:
```
"pub_key": {
"type": "ed25519",
"data": "83DDF8775937A4A12A2704269E2729FCFCD491B933C4B0A7FFE37FE41D7760D0"
}
```
- Remove type information about RPC responses, so `[TypeByte, {"jsonrpc": "2.0", ... }]` is now just `{"jsonrpc": "2.0", ... }`
- Change `[]byte` to `data.Bytes` in all serialized types (for hex encoding)
- Lowercase the JSON tags in `ValidatorSet` fields
- Introduce `EventDataInner` for serializing events
- Other:
- Send InitChain message in handshake if `appBlockHeight == 0`
- Do not include the `Accum` field when computing the validator hash. This makes the ValidatorSetHash unique for a given validator set, rather than changing with every block (as the Accum changes)
- Unsafe RPC calls are not enabled by default. This includes `/dial_seeds`, and all calls prefixed with `unsafe`. Use the `--rpc.unsafe` flag to enable.
FEATURES:
- Per-module log levels. For instance, the new default is `state:info,*:error`, which means the `state` package logs at `info` level, and everything else logs at `error` level
- Log if a node is validator or not in every consensus round
- Use ldflags to set git hash as part of the version
- Ignore `address` and `pub_key` fields in `priv_validator.json` and overwrite them with the values derrived from the `priv_key`
IMPROVEMENTS:
- Merge `tendermint/go-p2p -> tendermint/tendermint/p2p` and `tendermint/go-rpc -> tendermint/tendermint/rpc/lib`
- Update paths for grand repo merge:
- `go-common -> tmlibs/common`
- `go-data -> go-wire/data`
- All other `go-` libs, except `go-crypto` and `go-wire`, are merged under `tmlibs`
- No global loggers (loggers are passed into constructors, or preferably set with a SetLogger method)
- Return HTTP status codes with errors for RPC responses
- Limit `/blockchain_info` call to return a maximum of 20 blocks
- Use `.Wrap()` and `.Unwrap()` instead of eg. `PubKeyS` for `go-crypto` types
- RPC JSON responses use pretty printing (via `json.MarshalIndent`)
- Color code different instances of the consensus for tests
- Isolate viper to `cmd/tendermint/commands` and do not read config from file for tests
## 0.9.2 (April 26, 2017)
BUG FIXES:
@ -24,7 +442,7 @@ IMPROVEMENTS:
- WAL uses #ENDHEIGHT instead of #HEIGHT (#HEIGHT will stop working in 0.10.0)
- Peers included via `--seeds`, under `seeds` in the config, or in `/dial_seeds` are now persistent, and will be reconnected to if the connection breaks
BUG FIXES:
BUG FIXES:
- Fix bug in fast-sync where we stop syncing after a peer is removed, even if they're re-added later
- Fix handshake replay to handle validator set changes and results of DeliverTx when we crash after app.Commit but before state.Save()
@ -40,7 +458,7 @@ message RequestQuery{
bytes data = 1;
string path = 2;
uint64 height = 3;
bool prove = 4;
bool prove = 4;
}
message ResponseQuery{
@ -64,7 +482,7 @@ type BlockMeta struct {
}
```
- `ValidatorSet.Proposer` is exposed as a field and persisted with the `State`. Use `GetProposer()` to initialize or update after validator-set changes.
- `ValidatorSet.Proposer` is exposed as a field and persisted with the `State`. Use `GetProposer()` to initialize or update after validator-set changes.
- `tendermint gen_validator` command output is now pure JSON
@ -107,7 +525,7 @@ type BlockID struct {
}
```
- `Vote` data type now includes validator address and index:
- `Vote` data type now includes validator address and index:
```
type Vote struct {
@ -127,7 +545,7 @@ type Vote struct {
FEATURES:
- New message type on the ConsensusReactor, `Maj23Msg`, for peers to alert others they've seen a Maj23,
- New message type on the ConsensusReactor, `Maj23Msg`, for peers to alert others they've seen a Maj23,
in order to track and handle conflicting votes intelligently to prevent Byzantine faults from causing halts:
```
@ -150,7 +568,7 @@ IMPROVEMENTS:
- Less verbose logging
- Better test coverage (37% -> 49%)
- Canonical SignBytes for signable types
- Write-Ahead Log for Mempool and Consensus via go-autofile
- Write-Ahead Log for Mempool and Consensus via tmlibs/autofile
- Better in-process testing for the consensus reactor and byzantine faults
- Better crash/restart testing for individual nodes at preset failure points, and of networks at arbitrary points
- Better abstraction over timeout mechanics
@ -230,7 +648,7 @@ FEATURES:
- TMSP and RPC support TCP and UNIX sockets
- Addition config options including block size and consensus parameters
- New WAL mode `cswal_light`; logs only the validator's own votes
- New RPC endpoints:
- New RPC endpoints:
- for starting/stopping profilers, and for updating config
- `/broadcast_tx_commit`, returns when tx is included in a block, else an error
- `/unsafe_flush_mempool`, empties the mempool
@ -251,14 +669,14 @@ BUG FIXES:
Strict versioning only began with the release of v0.7.0, in late summer 2016.
The project itself began in early summer 2014 and was workable decentralized cryptocurrency software by the end of that year.
Through the course of 2015, in collaboration with Eris Industries (now Monax Indsutries),
Through the course of 2015, in collaboration with Eris Industries (now Monax Indsutries),
many additional features were integrated, including an implementation from scratch of the Ethereum Virtual Machine.
That implementation now forms the heart of [ErisDB](https://github.com/eris-ltd/eris-db).
That implementation now forms the heart of [Burrow](https://github.com/hyperledger/burrow).
In the later half of 2015, the consensus algorithm was upgraded with a more asynchronous design and a more deterministic and robust implementation.
By late 2015, frustration with the difficulty of forking a large monolithic stack to create alternative cryptocurrency designs led to the
By late 2015, frustration with the difficulty of forking a large monolithic stack to create alternative cryptocurrency designs led to the
invention of the Application Blockchain Interface (ABCI), then called the Tendermint Socket Protocol (TMSP).
The Ethereum Virtual Machine and various other transaction features were removed, and Tendermint was whittled down to a core consensus engine
driving an application running in another process.
driving an application running in another process.
The ABCI interface and implementation were iterated on and improved over the course of 2016,
until versioned history kicked in with v0.7.0.

56
CODE_OF_CONDUCT.md Normal file
View File

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

View File

@ -1,16 +1,117 @@
# Contributing guidelines
# Contributing
**Thanks for considering making contributions to Tendermint!**
Thank you for considering making contributions to Tendermint and related repositories! Start by taking a look at the [coding repo](https://github.com/tendermint/coding) for overall information on repository workflow and standards.
Please follow standard github best practices: fork the repo, **branch from the
tip of develop**, make some commits, test your code changes with `make test`,
and submit a pull request to develop.
Please follow standard github best practices: fork the repo, branch from the tip of develop, make some commits, and submit a pull request to develop. See the [open issues](https://github.com/tendermint/tendermint/issues) for things we need help with!
See the [open issues](https://github.com/tendermint/tendermint/issues) for
things we need help with!
Please make sure to use `gofmt` before every commit - the easiest way to do this is have your editor run it for you upon saving a file.
Please make sure to use `gofmt` before every commit - the easiest way to do
this is have your editor run it for you upon saving a file.
## Forking
You can read the full guide [on our
site](https://tendermint.com/docs/guides/contributing).
Please note that Go requires code to live under absolute paths, which complicates forking.
While my fork lives at `https://github.com/ebuchman/tendermint`,
the code should never exist at `$GOPATH/src/github.com/ebuchman/tendermint`.
Instead, we use `git remote` to add the fork as a new remote for the original repo,
`$GOPATH/src/github.com/tendermint/tendermint `, and do all the work there.
For instance, to create a fork and work on a branch of it, I would:
* Create the fork on github, using the fork button.
* Go to the original repo checked out locally (ie. `$GOPATH/src/github.com/tendermint/tendermint`)
* `git remote rename origin upstream`
* `git remote add origin git@github.com:ebuchman/basecoin.git`
Now `origin` refers to my fork and `upstream` refers to the tendermint version.
So I can `git push -u origin master` to update my fork, and make pull requests to tendermint from there.
Of course, replace `ebuchman` with your git handle.
To pull in updates from the origin repo, run
* `git fetch upstream`
* `git rebase upstream/master` (or whatever branch you want)
Please don't make Pull Requests to `master`.
## Dependencies
We use [dep](https://github.com/golang/dep) to manage dependencies.
That said, the master branch of every Tendermint repository should just build
with `go get`, which means they should be kept up-to-date with their
dependencies so we can get away with telling people they can just `go get` our
software.
Since some dependencies are not under our control, a third party may break our
build, in which case we can fall back on `dep ensure` (or `make
get_vendor_deps`). Even for dependencies under our control, dep helps us to
keep multiple repos in sync as they evolve. Anything with an executable, such
as apps, tools, and the core, should use dep.
Run `dep status` to get a list of vendored dependencies that may not be
up-to-date.
## Vagrant
If you are a [Vagrant](https://www.vagrantup.com/) user, you can get started
hacking Tendermint with the commands below.
NOTE: In case you installed Vagrant in 2017, you might need to run
`vagrant box update` to upgrade to the latest `ubuntu/xenial64`.
```
vagrant up
vagrant ssh
make test
```
## Testing
All repos should be hooked up to [CircleCI](https://circleci.com/).
If they have `.go` files in the root directory, they will be automatically
tested by circle using `go test -v -race ./...`. If not, they will need a
`circle.yml`. Ideally, every repo has a `Makefile` that defines `make test` and
includes its continuous integration status using a badge in the `README.md`.
## Branching Model and Release
User-facing repos should adhere to the branching model: http://nvie.com/posts/a-successful-git-branching-model/.
That is, these repos should be well versioned, and any merge to master requires a version bump and tagged release.
Libraries need not follow the model strictly, but would be wise to,
especially `go-p2p` and `go-rpc`, as their versions are referenced in tendermint core.
### Development Procedure:
- the latest state of development is on `develop`
- `develop` must never fail `make test`
- no --force onto `develop` (except when reverting a broken commit, which should seldom happen)
- create a development branch either on github.com/tendermint/tendermint, or your fork (using `git add origin`)
- before submitting a pull request, begin `git rebase` on top of `develop`
### Pull Merge Procedure:
- ensure pull branch is rebased on develop
- run `make test` to ensure that all tests pass
- merge pull request
- the `unstable` branch may be used to aggregate pull merges before testing once
- push master may request that pull requests be rebased on top of `unstable`
### Release Procedure:
- start on `develop`
- run integration tests (see `test_integrations` in Makefile)
- prepare changelog/release issue
- bump versions
- push to release-vX.X.X to run the extended integration tests on the CI
- merge to master
- merge master back to develop
### Hotfix Procedure:
- start on `master`
- checkout a new branch named hotfix-vX.X.X
- make the required changes
- these changes should be small and an absolute necessity
- add a note to CHANGELOG.md
- bumb versions
- push to hotfix-vX.X.X to run the extended integration tests on the CI
- merge hotfix-vX.X.X to master
- merge hotfix-vX.X.X to develop
- delete the hotfix-vX.X.X branch

View File

@ -1,8 +1,8 @@
FROM alpine:3.5
FROM alpine:3.7
# This is the release of tendermint to pull in.
ENV TM_VERSION 0.9.0
ENV TM_SHA256SUM 697033ea0f34f8b34a8a2b74c4dd730b47dd4efcfce65e53e953bdae8eb14364
ENV TM_VERSION 0.17.1
ENV TM_SHA256SUM d57008c63d2d9176861137e38ed203da486febf20ae7d388fb810a75afff8f24
# Tendermint will be looking for genesis file in /tendermint (unless you change
# `genesis_file` in config.toml). You can put your config.toml and private
@ -26,7 +26,7 @@ RUN mkdir -p $DATA_ROOT && \
RUN apk add --no-cache bash curl jq
RUN apk add --no-cache openssl && \
wget https://s3-us-west-2.amazonaws.com/tendermint/${TM_VERSION}/tendermint_${TM_VERSION}_linux_amd64.zip && \
wget https://github.com/tendermint/tendermint/releases/download/v${TM_VERSION}/tendermint_${TM_VERSION}_linux_amd64.zip && \
echo "${TM_SHA256SUM} tendermint_${TM_VERSION}_linux_amd64.zip" | sha256sum -c && \
unzip -d /bin tendermint_${TM_VERSION}_linux_amd64.zip && \
apk del openssl && \
@ -42,5 +42,4 @@ EXPOSE 46657
ENTRYPOINT ["tendermint"]
# By default you'll get the dummy app
CMD ["node", "--moniker=`hostname`", "--proxy_app=dummy"]
CMD ["node", "--moniker=`hostname`"]

View File

@ -1,4 +1,4 @@
FROM alpine:3.5
FROM alpine:3.7
ENV DATA_ROOT /tendermint
ENV TMHOME $DATA_ROOT
@ -18,9 +18,9 @@ RUN mkdir -p /go/src/github.com/tendermint/tendermint && \
cd /go/src/github.com/tendermint/tendermint && \
git clone https://github.com/tendermint/tendermint . && \
git checkout develop && \
make get_tools && \
make get_vendor_deps && \
make install && \
glide cc && \
cd - && \
rm -rf /go/src/github.com/tendermint/tendermint && \
apk del go build-base git
@ -32,4 +32,4 @@ EXPOSE 46657
ENTRYPOINT ["tendermint"]
CMD ["node", "--moniker=`hostname`", "--proxy_app=dummy"]
CMD ["node", "--moniker=`hostname`", "--proxy_app=kvstore"]

View File

@ -1,10 +1,8 @@
build:
# TAG=0.8.0 TAG_NO_PATCH=0.8
docker build -t "tendermint/tendermint" -t "tendermint/tendermint:$TAG" -t "tendermint/tendermint:$TAG_NO_PATCH" .
@sh -c "'$(CURDIR)/build.sh'"
push:
# TAG=0.8.0 TAG_NO_PATCH=0.8
docker push "tendermint/tendermint" "tendermint/tendermint:$TAG" "tendermint/tendermint:$TAG_NO_PATCH"
@sh -c "'$(CURDIR)/push.sh'"
build_develop:
docker build -t "tendermint/tendermint:develop" -f Dockerfile.develop .

View File

@ -1,41 +1,52 @@
# Supported tags and respective `Dockerfile` links
- `0.9.0`, `0.9`, `latest` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/d474baeeea6c22b289e7402449572f7c89ee21da/DOCKER/Dockerfile)
- `0.17.1`, `latest` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/208ac32fa266657bd6c304e84ec828aa252bb0b8/DOCKER/Dockerfile)
- `0.15.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/170777300ea92dc21a8aec1abc16cb51812513a4/DOCKER/Dockerfile)
- `0.13.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/a28b3fff49dce2fb31f90abb2fc693834e0029c2/DOCKER/Dockerfile)
- `0.12.1` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/457c688346b565e90735431619ca3ca597ef9007/DOCKER/Dockerfile)
- `0.12.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/70d8afa6e952e24c573ece345560a5971bf2cc0e/DOCKER/Dockerfile)
- `0.11.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/9177cc1f64ca88a4a0243c5d1773d10fba67e201/DOCKER/Dockerfile)
- `0.10.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/e5342f4054ab784b2cd6150e14f01053d7c8deb2/DOCKER/Dockerfile)
- `0.9.1`, `0.9`, [(Dockerfile)](https://github.com/tendermint/tendermint/blob/809e0e8c5933604ba8b2d096803ada7c5ec4dfd3/DOCKER/Dockerfile)
- `0.9.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/d474baeeea6c22b289e7402449572f7c89ee21da/DOCKER/Dockerfile)
- `0.8.0`, `0.8` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/bf64dd21fdb193e54d8addaaaa2ecf7ac371de8c/DOCKER/Dockerfile)
- `develop` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/master/DOCKER/Dockerfile.develop)
`develop` tag points to the [develop](https://github.com/tendermint/tendermint/tree/develop) branch.
# Quick reference
* **Where to get help:**
https://tendermint.com/community
* **Where to file issues:**
https://github.com/tendermint/tendermint/issues
* **Supported Docker versions:**
[the latest release](https://github.com/moby/moby/releases) (down to 1.6 on a best-effort basis)
# Tendermint
Tendermint Core is Byzantine Fault Tolerant (BFT) middleware that takes a state transition machine, written in any programming language, and securely replicates it on many machines.
For more background, see the [introduction](https://tendermint.com/intro).
For more background, see the [introduction](https://tendermint.readthedocs.io/en/master/introduction.html).
To get started developing applications, see the [application developers guide](https://tendermint.com/docs/guides/app-development).
To get started developing applications, see the [application developers guide](https://tendermint.readthedocs.io/en/master/getting-started.html).
# How to use this image
## Start one instance of the Tendermint core with the `dummy` app
## Start one instance of the Tendermint core with the `kvstore` app
A very simple example of a built-in app and Tendermint core in one container.
```
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint init
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint node --proxy_app=kvstore
```
## mintnet-kubernetes
If you want to see many containers talking to each other, consider using [mintnet-kubernetes](https://github.com/tendermint/mintnet-kubernetes), which is a tool for running Tendermint-based applications on a Kubernetes cluster.
# Supported Docker versions
This image is officially supported on Docker version 1.13.1.
Support for older versions (down to 1.6) is provided on a best-effort basis.
Please see [the Docker installation documentation](https://docs.docker.com/installation/) for details on how to upgrade your Docker daemon.
If you want to see many containers talking to each other, consider using [mintnet-kubernetes](https://github.com/tendermint/tools/tree/master/mintnet-kubernetes), which is a tool for running Tendermint-based applications on a Kubernetes cluster.
# License
@ -43,12 +54,6 @@ View [license information](https://raw.githubusercontent.com/tendermint/tendermi
# User Feedback
## Issues
If you have any problems with or questions about this image, please contact us through a [GitHub](https://github.com/tendermint/tendermint/issues) issue. If the issue is related to a CVE, please check for [a `cve-tracker` issue on the `official-images` repository](https://github.com/docker-library/official-images/issues?q=label%3Acve-tracker) first.
You can also reach the image maintainers via [Slack](http://forum.tendermint.com:3000/).
## Contributing
You are invited to contribute new features, fixes, or updates, large or small; we are always thrilled to receive pull requests, and do our best to process them as fast as we can.

20
DOCKER/build.sh Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
# Get the tag from the version, or try to figure it out.
if [ -z "$TAG" ]; then
TAG=$(awk -F\" '/Version =/ { print $2; exit }' < ../version/version.go)
fi
if [ -z "$TAG" ]; then
echo "Please specify a tag."
exit 1
fi
TAG_NO_PATCH=${TAG%.*}
read -p "==> Build 3 docker images with the following tags (latest, $TAG, $TAG_NO_PATCH)? y/n" -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
docker build -t "tendermint/tendermint" -t "tendermint/tendermint:$TAG" -t "tendermint/tendermint:$TAG_NO_PATCH" .
fi

22
DOCKER/push.sh Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -e
# Get the tag from the version, or try to figure it out.
if [ -z "$TAG" ]; then
TAG=$(awk -F\" '/Version =/ { print $2; exit }' < ../version/version.go)
fi
if [ -z "$TAG" ]; then
echo "Please specify a tag."
exit 1
fi
TAG_NO_PATCH=${TAG%.*}
read -p "==> Push 3 docker images with the following tags (latest, $TAG, $TAG_NO_PATCH)? y/n" -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
docker push "tendermint/tendermint:latest"
docker push "tendermint/tendermint:$TAG"
docker push "tendermint/tendermint:$TAG_NO_PATCH"
fi

388
Gopkg.lock generated Normal file
View File

@ -0,0 +1,388 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/btcsuite/btcd"
packages = ["btcec"]
revision = "2be2f12b358dc57d70b8f501b00be450192efbc3"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/ebuchman/fail-test"
packages = ["."]
revision = "95f809107225be108efcf10a3509e4ea6ceef3c4"
[[projects]]
name = "github.com/fortytw2/leaktest"
packages = ["."]
revision = "a5ef70473c97b71626b9abeda80ee92ba2a7de9e"
version = "v1.2.0"
[[projects]]
name = "github.com/fsnotify/fsnotify"
packages = ["."]
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
version = "v1.4.7"
[[projects]]
name = "github.com/go-kit/kit"
packages = [
"log",
"log/level",
"log/term"
]
revision = "4dc7be5d2d12881735283bcab7352178e190fc71"
version = "v0.6.0"
[[projects]]
name = "github.com/go-logfmt/logfmt"
packages = ["."]
revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5"
version = "v0.3.0"
[[projects]]
name = "github.com/go-stack/stack"
packages = ["."]
revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc"
version = "v1.7.0"
[[projects]]
name = "github.com/gogo/protobuf"
packages = [
"gogoproto",
"jsonpb",
"proto",
"protoc-gen-gogo/descriptor",
"sortkeys",
"types"
]
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
version = "v1.0.0"
[[projects]]
name = "github.com/golang/protobuf"
packages = [
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp"
]
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/golang/snappy"
packages = ["."]
revision = "553a641470496b2327abcac10b36396bd98e45c9"
[[projects]]
name = "github.com/gorilla/websocket"
packages = ["."]
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[[projects]]
branch = "master"
name = "github.com/hashicorp/hcl"
packages = [
".",
"hcl/ast",
"hcl/parser",
"hcl/printer",
"hcl/scanner",
"hcl/strconv",
"hcl/token",
"json/parser",
"json/scanner",
"json/token"
]
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
[[projects]]
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0"
[[projects]]
branch = "master"
name = "github.com/jmhodges/levigo"
packages = ["."]
revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9"
[[projects]]
branch = "master"
name = "github.com/kr/logfmt"
packages = ["."]
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
[[projects]]
name = "github.com/magiconair/properties"
packages = ["."]
revision = "c3beff4c2358b44d0493c7dda585e7db7ff28ae6"
version = "v1.7.6"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
revision = "00c29f56e2386353d58c599509e8dc3801b0d716"
[[projects]]
name = "github.com/pelletier/go-toml"
packages = ["."]
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
version = "v1.1.0"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/rcrowley/go-metrics"
packages = ["."]
revision = "d932a24a8ccb8fcadc993e5c6c58f93dac168294"
[[projects]]
name = "github.com/spf13/afero"
packages = [
".",
"mem"
]
revision = "63644898a8da0bc22138abf860edaf5277b6102e"
version = "v1.1.0"
[[projects]]
name = "github.com/spf13/cast"
packages = ["."]
revision = "8965335b8c7107321228e3e3702cab9832751bac"
version = "v1.2.0"
[[projects]]
name = "github.com/spf13/cobra"
packages = ["."]
revision = "a1f051bc3eba734da4772d60e2d677f47cf93ef4"
version = "v0.0.2"
[[projects]]
branch = "master"
name = "github.com/spf13/jwalterweatherman"
packages = ["."]
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
[[projects]]
name = "github.com/spf13/pflag"
packages = ["."]
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
version = "v1.0.1"
[[projects]]
name = "github.com/spf13/viper"
packages = ["."]
revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
version = "v1.0.2"
[[projects]]
name = "github.com/stretchr/testify"
packages = [
"assert",
"require"
]
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
version = "v1.2.1"
[[projects]]
branch = "master"
name = "github.com/syndtr/goleveldb"
packages = [
"leveldb",
"leveldb/cache",
"leveldb/comparer",
"leveldb/errors",
"leveldb/filter",
"leveldb/iterator",
"leveldb/journal",
"leveldb/memdb",
"leveldb/opt",
"leveldb/storage",
"leveldb/table",
"leveldb/util"
]
revision = "714f901b98fdb3aa954b4193d8cbd64a28d80cad"
[[projects]]
name = "github.com/tendermint/abci"
packages = [
"client",
"example/code",
"example/counter",
"example/kvstore",
"server",
"types"
]
revision = "78a8905690ef54f9d57e3b2b0ee7ad3a04ef3f1f"
version = "v0.10.3"
[[projects]]
branch = "master"
name = "github.com/tendermint/ed25519"
packages = [
".",
"edwards25519",
"extra25519"
]
revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057"
[[projects]]
name = "github.com/tendermint/go-amino"
packages = ["."]
revision = "42246108ff925a457fb709475070a03dfd3e2b5c"
version = "0.9.6"
[[projects]]
name = "github.com/tendermint/go-crypto"
packages = ["."]
revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19"
version = "v0.6.2"
[[projects]]
name = "github.com/tendermint/go-wire"
packages = ["."]
revision = "fa721242b042ecd4c6ed1a934ee740db4f74e45c"
version = "v0.7.3"
[[projects]]
name = "github.com/tendermint/tmlibs"
packages = [
"autofile",
"cli",
"cli/flags",
"clist",
"common",
"db",
"flowrate",
"log",
"merkle",
"pubsub",
"pubsub/query",
"test"
]
revision = "97e1f1ad3f510048929a51475811a18686c894df"
version = "0.8.2-rc0"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"curve25519",
"nacl/box",
"nacl/secretbox",
"openpgp/armor",
"openpgp/errors",
"poly1305",
"ripemd160",
"salsa20/salsa"
]
revision = "d6449816ce06963d9d136eee5a56fca5b0616e7e"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"context",
"http2",
"http2/hpack",
"idna",
"internal/timeseries",
"lex/httplex",
"trace"
]
revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "3b87a42e500a6dc65dae1a55d0b641295971163e"
[[projects]]
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable"
]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
revision = "51d0944304c3cbce4afe9e5247e21100037bff78"
[[projects]]
name = "google.golang.org/grpc"
packages = [
".",
"balancer",
"codes",
"connectivity",
"credentials",
"grpclb/grpc_lb_v1/messages",
"grpclog",
"internal",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"stats",
"status",
"tap",
"transport"
]
revision = "5b3c4e850e90a4cf6a20ebd46c8b32a0a3afcb9e"
version = "v1.7.5"
[[projects]]
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "e70f8692c825e80ae8510546e297840b9560d00e11b2272749a55cc2ffd147f0"
solver-name = "gps-cdcl"
solver-version = 1

94
Gopkg.toml Normal file
View File

@ -0,0 +1,94 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
name = "github.com/ebuchman/fail-test"
branch = "master"
[[constraint]]
name = "github.com/fortytw2/leaktest"
branch = "master"
[[constraint]]
name = "github.com/go-kit/kit"
version = "~0.6.0"
[[constraint]]
name = "github.com/gogo/protobuf"
version = "~1.0.0"
[[constraint]]
name = "github.com/golang/protobuf"
version = "~1.0.0"
[[constraint]]
name = "github.com/gorilla/websocket"
version = "~1.2.0"
[[constraint]]
name = "github.com/pkg/errors"
version = "~0.8.0"
[[constraint]]
name = "github.com/rcrowley/go-metrics"
branch = "master"
[[constraint]]
name = "github.com/spf13/cobra"
version = "~0.0.1"
[[constraint]]
name = "github.com/spf13/viper"
version = "~1.0.0"
[[constraint]]
name = "github.com/stretchr/testify"
version = "~1.2.1"
[[constraint]]
name = "github.com/tendermint/abci"
version = "~0.10.3"
[[constraint]]
name = "github.com/tendermint/go-crypto"
version = "~0.6.2"
[[constraint]]
name = "github.com/tendermint/go-amino"
version = "~0.9.6"
[[constraint]]
name = "github.com/tendermint/tmlibs"
version = "~0.8.2-rc0"
[[constraint]]
name = "google.golang.org/grpc"
version = "~1.7.3"
[prune]
go-tests = true
unused-packages = true

View File

@ -1,57 +0,0 @@
# Install Go
[Install Go, set the `GOPATH`, and put `GOPATH/bin` on your `PATH`](https://github.com/tendermint/tendermint/wiki/Setting-GOPATH).
# Install Tendermint
You should be able to install the latest with a simple `go get -u github.com/tendermint/tendermint/cmd/tendermint`.
The `-u` makes sure all dependencies are updated as well.
Run `tendermint version` and `tendermint --help`.
If the install falied, see [vendored dependencies below](#vendored-dependencies).
To start a one-node blockchain with a simple in-process application:
```
tendermint init
tendermint node --proxy_app=dummy
```
See the [application developers guide](https://github.com/tendermint/tendermint/wiki/Application-Developers) for more details on building and running applications.
## Vendored dependencies
If the `go get` failed, updated dependencies may have broken the build.
Install the correct version of each dependency using `glide`.
Fist, install `glide`:
```
go get github.com/Masterminds/glide
```
Now, fetch the dependencies and install them with `glide` and `go`:
```
cd $GOPATH/src/github.com/tendermint/tendermint
glide install
go install ./cmd/tendermint
```
Sometimes `glide install` is painfully slow. Hang in there champ.
The latest Tendermint Core version is now installed. Check by running `tendermint version`.
## Troubleshooting
If `go get` failing bothers you, fetch the code using `git`:
```
mkdir -p $GOPATH/src/github.com/tendermint
git clone https://github.com/tendermint/tendermint $GOPATH/src/github.com/tendermint/tendermint
cd $GOPATH/src/github.com/tendermint/tendermint
glide install
go install ./cmd/tendermint
```

212
Makefile
View File

@ -1,25 +1,135 @@
GOTOOLS = \
github.com/mitchellh/gox \
github.com/Masterminds/glide
github.com/golang/dep/cmd/dep \
gopkg.in/alecthomas/gometalinter.v2
PACKAGES=$(shell go list ./... | grep -v '/vendor/')
BUILD_TAGS?=tendermint
TMHOME = $${TMHOME:-$$HOME/.tendermint}
BUILD_FLAGS = -ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse --short=8 HEAD`"
all: install test
all: check build test install
install: get_vendor_deps
@go install ./cmd/tendermint
check: check_tools ensure_deps
########################################
### Build
build:
go build -o build/tendermint ./cmd/tendermint
CGO_ENABLED=0 go build $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' -o build/tendermint ./cmd/tendermint/
build_race:
go build -race -o build/tendermint ./cmd/tendermint
CGO_ENABLED=0 go build -race $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' -o build/tendermint ./cmd/tendermint
install:
CGO_ENABLED=0 go install $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' ./cmd/tendermint
########################################
### Distribution
# dist builds binaries for all platforms and packages them for distribution
dist:
@BUILD_TAGS='$(BUILD_TAGS)' sh -c "'$(CURDIR)/scripts/dist.sh'"
########################################
### Tools & dependencies
check_tools:
@# https://stackoverflow.com/a/25668869
@echo "Found tools: $(foreach tool,$(notdir $(GOTOOLS)),\
$(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))"
get_tools:
@echo "--> Installing tools"
go get -u -v $(GOTOOLS)
@gometalinter.v2 --install
update_tools:
@echo "--> Updating tools"
@go get -u $(GOTOOLS)
#Run this from CI
get_vendor_deps:
@rm -rf vendor/
@echo "--> Running dep"
@dep ensure -vendor-only
#Run this locally.
ensure_deps:
@rm -rf vendor/
@echo "--> Running dep"
@dep ensure
draw_deps:
@# requires brew install graphviz or apt-get install graphviz
go get github.com/RobotsAndPencils/goviz
@goviz -i github.com/tendermint/tendermint/cmd/tendermint -d 3 | dot -Tpng -o dependency-graph.png
get_deps_bin_size:
@# Copy of build recipe with additional flags to perform binary size analysis
$(eval $(shell go build -work -a $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' -o build/tendermint ./cmd/tendermint/ 2>&1))
@find $(WORK) -type f -name "*.a" | xargs -I{} du -hxs "{}" | sort -rh | sed -e s:${WORK}/::g > deps_bin_size.log
@echo "Results can be found here: $(CURDIR)/deps_bin_size.log"
########################################
### Testing
## required to be run first by most tests
build_docker_test_image:
docker build -t tester -f ./test/docker/Dockerfile .
### coverage, app, persistence, and libs tests
test_cover:
# run the go unit tests with coverage
bash test/test_cover.sh
test_apps:
# run the app tests using bash
# requires `abci-cli` and `tendermint` binaries installed
bash test/app/test.sh
test_persistence:
# run the persistence tests using bash
# requires `abci-cli` installed
docker run --name run_persistence -t tester bash test/persist/test_failure_indices.sh
# TODO undockerize
# bash test/persist/test_failure_indices.sh
test_p2p:
docker rm -f rsyslog || true
rm -rf test/logs || true
mkdir test/logs
cd test/
docker run -d -v "logs:/var/log/" -p 127.0.0.1:5514:514/udp --name rsyslog voxxit/rsyslog
cd ..
# requires 'tester' the image from above
bash test/p2p/test.sh tester
need_abci:
bash scripts/install_abci_apps.sh
test_integrations:
make build_docker_test_image
make get_tools
make get_vendor_deps
make install
make need_abci
make test_cover
make test_apps
make test_persistence
make test_p2p
test_release:
@go test -tags release $(PACKAGES)
test100:
@for i in {1..100}; do make test; done
vagrant_test:
vagrant up
vagrant ssh -c 'make test_integrations'
### go tests
test:
@echo "--> Running go test"
@go test $(PACKAGES)
@ -28,47 +138,65 @@ test_race:
@echo "--> Running go test --race"
@go test -v -race $(PACKAGES)
test_integrations:
@bash ./test/test.sh
test100:
@for i in {1..100}; do make test; done
########################################
### Formatting, linting, and vetting
draw_deps:
# requires brew install graphviz or apt-get install graphviz
go get github.com/RobotsAndPencils/goviz
@goviz -i github.com/tendermint/tendermint/cmd/tendermint -d 3 | dot -Tpng -o dependency-graph.png
fmt:
@go fmt ./...
list_deps:
@go list -f '{{join .Deps "\n"}}' ./... | \
grep -v /vendor/ | sort | uniq | \
xargs go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}'
metalinter:
@echo "--> Running linter"
@gometalinter.v2 --vendor --deadline=600s --disable-all \
--enable=deadcode \
--enable=gosimple \
--enable=misspell \
--enable=safesql \
./...
#--enable=gas \
#--enable=maligned \
#--enable=dupl \
#--enable=errcheck \
#--enable=goconst \
#--enable=gocyclo \
#--enable=goimports \
#--enable=golint \ <== comments on anything exported
#--enable=gotype \
#--enable=ineffassign \
#--enable=interfacer \
#--enable=megacheck \
#--enable=staticcheck \
#--enable=structcheck \
#--enable=unconvert \
#--enable=unparam \
#--enable=unused \
#--enable=varcheck \
#--enable=vet \
#--enable=vetshadow \
get_deps:
@echo "--> Running go get"
@go get -v -d $(PACKAGES)
@go list -f '{{join .TestImports "\n"}}' ./... | \
grep -v /vendor/ | sort | uniq | \
xargs go get -v -d
metalinter_all:
@echo "--> Running linter (all)"
gometalinter.v2 --vendor --deadline=600s --enable-all --disable=lll ./...
get_vendor_deps: ensure_tools
@rm -rf vendor/
@echo "--> Running glide install"
@glide install
###########################################################
### Local testnet using docker
update_deps: tools
@echo "--> Updating dependencies"
@go get -d -u ./...
# Build linux binary on other platforms
build-linux:
GOOS=linux GOARCH=amd64 $(MAKE) build
revision:
-echo `git rev-parse --verify HEAD` > $(TMHOME)/revision
-echo `git rev-parse --verify HEAD` >> $(TMHOME)/revision_history
# Run a 4-node testnet locally
docker-start:
@echo "Wait until 'Attaching to node0, node1, node2, node3' message appears"
@if ! [ -f build/node0/config/genesis.json ]; then docker run --rm -v `pwd`/build:/tendermint:Z tendermint/localnode testnet --v 4 --o . --populate-persistent-peers --starting-ip-address 192.167.10.2 ; fi
docker-compose up
tools:
go get -u -v $(GOTOOLS)
# Stop testnet
docker-stop:
docker-compose down
ensure_tools:
go get $(GOTOOLS)
# To avoid unintended conflicts with file names, always add to .PHONY
# unless there is a reason not to.
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: check build build_race dist install check_tools get_tools update_tools get_vendor_deps draw_deps test_cover test_apps test_persistence test_p2p test test_race test_integrations test_release test100 vagrant_test fmt build-linux docker-start docker-stop
.PHONY: install build build_race dist test test_race test_integrations test100 draw_deps list_deps get_deps get_vendor_deps update_deps revision tools

View File

@ -1,71 +1,112 @@
# Tendermint
[Byzantine-Fault Tolerant](https://en.wikipedia.org/wiki/Byzantine_fault_tolerance)
[State Machine Replication](https://en.wikipedia.org/wiki/State_machine_replication).
[State Machine Replication](https://en.wikipedia.org/wiki/State_machine_replication).
Or [Blockchain](https://en.wikipedia.org/wiki/Blockchain_(database)) for short.
[![version](https://img.shields.io/github/tag/tendermint/tendermint.svg)](https://github.com/tendermint/tendermint/releases/latest)
[![API Reference](
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
)](https://godoc.org/github.com/tendermint/tendermint)
[![chat](https://img.shields.io/badge/slack-join%20chat-pink.svg)](http://forum.tendermint.com:3000/)
[![Go version](https://img.shields.io/badge/go-1.9.2-blue.svg)](https://github.com/moovweb/gvm)
[![Rocket.Chat](https://demo.rocket.chat/images/join-chat.svg)](https://cosmos.rocket.chat/)
[![license](https://img.shields.io/github/license/tendermint/tendermint.svg)](https://github.com/tendermint/tendermint/blob/master/LICENSE)
[![](https://tokei.rs/b1/github/tendermint/tendermint?category=lines)](https://github.com/tendermint/tendermint)
Branch | Tests | Coverage | Report Card
----------|-------|----------|-------------
develop | [![CircleCI](https://circleci.com/gh/tendermint/tendermint/tree/develop.svg?style=shield)](https://circleci.com/gh/tendermint/tendermint/tree/develop) | [![codecov](https://codecov.io/gh/tendermint/tendermint/branch/develop/graph/badge.svg)](https://codecov.io/gh/tendermint/tendermint) | [![Go Report Card](https://goreportcard.com/badge/github.com/tendermint/tendermint/tree/develop)](https://goreportcard.com/report/github.com/tendermint/tendermint/tree/develop)
master | [![CircleCI](https://circleci.com/gh/tendermint/tendermint/tree/master.svg?style=shield)](https://circleci.com/gh/tendermint/tendermint/tree/master) | [![codecov](https://codecov.io/gh/tendermint/tendermint/branch/master/graph/badge.svg)](https://codecov.io/gh/tendermint/tendermint) | [![Go Report Card](https://goreportcard.com/badge/github.com/tendermint/tendermint/tree/master)](https://goreportcard.com/report/github.com/tendermint/tendermint/tree/master)
Branch | Tests | Coverage
----------|-------|----------
master | [![CircleCI](https://circleci.com/gh/tendermint/tendermint/tree/master.svg?style=shield)](https://circleci.com/gh/tendermint/tendermint/tree/master) | [![codecov](https://codecov.io/gh/tendermint/tendermint/branch/master/graph/badge.svg)](https://codecov.io/gh/tendermint/tendermint)
develop | [![CircleCI](https://circleci.com/gh/tendermint/tendermint/tree/develop.svg?style=shield)](https://circleci.com/gh/tendermint/tendermint/tree/develop) | [![codecov](https://codecov.io/gh/tendermint/tendermint/branch/develop/graph/badge.svg)](https://codecov.io/gh/tendermint/tendermint)
_NOTE: This is alpha software. Please contact us if you intend to run it in production._
Tendermint Core is Byzantine Fault Tolerant (BFT) middleware that takes a state transition machine, written in any programming language,
Tendermint Core is Byzantine Fault Tolerant (BFT) middleware that takes a state transition machine - written in any programming language -
and securely replicates it on many machines.
For more background, see the [introduction](https://tendermint.com/intro).
For more information, from introduction to install to application development, [Read The Docs](https://tendermint.readthedocs.io/en/master/).
To get started developing applications, see the [application developers guide](https://tendermint.com/docs/guides/app-development).
## Minimum requirements
Requirement|Notes
---|---
Go version | Go1.9 or higher
## Install
To download pre-built binaries, see our [downloads page](https://tendermint.com/intro/getting-started/download).
To download pre-built binaries, see our [downloads page](https://tendermint.com/downloads).
To install from source, you should be able to:
`go get -u github.com/tendermint/tendermint/cmd/tendermint`
For more details (or if it fails), see the [install guide](https://tendermint.com/docs/guides/install).
## Contributing
Yay open source! Please see our [contributing guidelines](https://tendermint.com/docs/guides/contributing).
For more details (or if it fails), [read the docs](https://tendermint.readthedocs.io/en/master/install.html).
## Resources
### Tendermint Core
- [Introduction](https://tendermint.com/intro)
- [Docs](https://tendermint.com/docs)
- [Software using Tendermint](https://tendermint.com/ecosystem)
All resources involving the use of, building application on, or developing for, tendermint, can be found at [Read The Docs](https://tendermint.readthedocs.io/en/master/). Additional information about some - and eventually all - of the sub-projects below, can be found at Read The Docs.
### Sub-projects
* [ABCI](http://github.com/tendermint/abci)
* [Mintnet](http://github.com/tendermint/mintnet)
* [Go-Wire](http://github.com/tendermint/go-wire)
* [Go-P2P](http://github.com/tendermint/go-p2p)
* [Go-Merkle](http://github.com/tendermint/go-merkle)
* [ABCI](http://github.com/tendermint/abci), the Application Blockchain Interface
* [Go-Wire](http://github.com/tendermint/go-wire), a deterministic serialization library
* [Go-Crypto](http://github.com/tendermint/go-crypto), an elliptic curve cryptography library
* [TmLibs](http://github.com/tendermint/tmlibs), an assortment of Go libraries used internally
* [IAVL](http://github.com/tendermint/iavl), Merkleized IAVL+ Tree implementation
### Tools
* [Deployment, Benchmarking, and Monitoring](http://tendermint.readthedocs.io/projects/tools/en/develop/index.html#tendermint-tools)
### Applications
* [Ethermint](http://github.com/tendermint/ethermint)
* [Basecoin](http://github.com/tendermint/basecoin)
* [Ethermint](http://github.com/tendermint/ethermint); Ethereum on Tendermint
* [Cosmos SDK](http://github.com/cosmos/cosmos-sdk); a cryptocurrency application framework
* [Many more](https://tendermint.readthedocs.io/en/master/ecosystem.html#abci-applications)
### More
### More
* [Tendermint Blog](https://tendermint.com/blog)
* [Cosmos Blog](https://cosmos.network/blog)
* [Original Whitepaper (out-of-date)](http://www.the-blockchain.com/docs/Tendermint%20Consensus%20without%20Mining.pdf)
* [Master's Thesis on Tendermint](https://atrium.lib.uoguelph.ca/xmlui/handle/10214/9769)
* [Original Whitepaper](https://tendermint.com/static/docs/tendermint.pdf)
* [Tendermint Blog](https://blog.cosmos.network/tendermint/home)
* [Cosmos Blog](https://blog.cosmos.network)
## Contributing
Yay open source! Please see our [contributing guidelines](CONTRIBUTING.md).
## Versioning
### SemVer
Tendermint uses [SemVer](http://semver.org/) to determine when and how the version changes.
According to SemVer, anything in the public API can change at any time before version 1.0.0
To provide some stability to Tendermint users in these 0.X.X days, the MINOR version is used
to signal breaking changes across a subset of the total public API. This subset includes all
interfaces exposed to other processes (cli, rpc, p2p, etc.), as well as parts of the following packages:
- types
- rpc/client
- config
- node
Exported objects in these packages that are not covered by the versioning scheme
are explicitly marked by `// UNSTABLE` in their go doc comment and may change at any time.
Functions, types, and values in any other package may also change at any time.
### Upgrades
In an effort to avoid accumulating technical debt prior to 1.0.0,
we do not guarantee that breaking changes (ie. bumps in the MINOR version)
will work with existing tendermint blockchains. In these cases you will
have to start a new blockchain, or write something custom to get the old
data into the new chain.
However, any bump in the PATCH version should be compatible with existing histories
(if not please open an [issue](https://github.com/tendermint/tendermint/issues)).
## Code of Conduct
Please read, understand and adhere to our [code of conduct](CODE_OF_CONDUCT.md).

44
Vagrantfile vendored
View File

@ -2,37 +2,51 @@
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.box = "ubuntu/xenial64"
config.vm.provider "virtualbox" do |v|
v.memory = 3072
v.memory = 4096
v.cpus = 2
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y --no-install-recommends wget curl jq shellcheck bsdmainutils psmisc
# add docker repo
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable"
wget -qO- https://get.docker.com/ | sh
usermod -a -G docker vagrant
# and golang 1.9 support
# official repo doesn't have race detection runtime...
# add-apt-repository ppa:gophers/archive
add-apt-repository ppa:longsleep/golang-backports
# install base requirements
apt-get update
apt-get install -y --no-install-recommends wget curl jq zip \
make shellcheck bsdmainutils psmisc
apt-get install -y docker-ce golang-1.9-go
apt-get install -y language-pack-en
# cleanup
apt-get autoremove -y
curl -O https://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz
tar -xvf go1.8.linux-amd64.tar.gz
rm -rf /usr/local/go
mv go /usr/local
rm -f go1.8.linux-amd64.tar.gz
mkdir -p /home/vagrant/go/bin
echo 'export PATH=$PATH:/usr/local/go/bin:/home/vagrant/go/bin' >> /home/vagrant/.bash_profile
# needed for docker
usermod -a -G docker vagrant
# set env variables
echo 'export PATH=$PATH:/usr/lib/go-1.9/bin:/home/vagrant/go/bin' >> /home/vagrant/.bash_profile
echo 'export GOPATH=/home/vagrant/go' >> /home/vagrant/.bash_profile
echo 'export LC_ALL=en_US.UTF-8' >> /home/vagrant/.bash_profile
echo 'cd go/src/github.com/tendermint/tendermint' >> /home/vagrant/.bash_profile
mkdir -p /home/vagrant/go/bin
mkdir -p /home/vagrant/go/src/github.com/tendermint
ln -s /vagrant /home/vagrant/go/src/github.com/tendermint/tendermint
chown -R vagrant:vagrant /home/vagrant/go
chown vagrant:vagrant /home/vagrant/.bash_profile
su - vagrant -c 'cd /home/vagrant/go/src/github.com/tendermint/tendermint && make get_vendor_deps'
# get all deps and tools, ready to install/test
su - vagrant -c 'source /home/vagrant/.bash_profile'
su - vagrant -c 'cd /home/vagrant/go/src/github.com/tendermint/tendermint && make get_tools && make get_vendor_deps'
SHELL
end

13
appveyor.yml Normal file
View File

@ -0,0 +1,13 @@
version: 1.0.{build}
configuration: Release
platform:
- x64
- x86
clone_folder: c:\go\path\src\github.com\tendermint\tendermint
before_build:
- cmd: set GOPATH=%GOROOT%\path
- cmd: set PATH=%GOPATH%\bin;%PATH%
- cmd: make get_vendor_deps
build_script:
- cmd: make test
test: off

2
benchmarks/blockchain/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
data

View File

@ -0,0 +1,80 @@
#!/bin/bash
DATA=$GOPATH/src/github.com/tendermint/tendermint/benchmarks/blockchain/data
if [ ! -d $DATA ]; then
echo "no data found, generating a chain... (this only has to happen once)"
tendermint init --home $DATA
cp $DATA/config.toml $DATA/config2.toml
echo "
[consensus]
timeout_commit = 0
" >> $DATA/config.toml
echo "starting node"
tendermint node \
--home $DATA \
--proxy_app kvstore \
--p2p.laddr tcp://127.0.0.1:56656 \
--rpc.laddr tcp://127.0.0.1:56657 \
--log_level error &
echo "making blocks for 60s"
sleep 60
mv $DATA/config2.toml $DATA/config.toml
kill %1
echo "done generating chain."
fi
# validator node
HOME1=$TMPDIR$RANDOM$RANDOM
cp -R $DATA $HOME1
echo "starting validator node"
tendermint node \
--home $HOME1 \
--proxy_app kvstore \
--p2p.laddr tcp://127.0.0.1:56656 \
--rpc.laddr tcp://127.0.0.1:56657 \
--log_level error &
sleep 1
# downloader node
HOME2=$TMPDIR$RANDOM$RANDOM
tendermint init --home $HOME2
cp $HOME1/genesis.json $HOME2
printf "starting downloader node"
tendermint node \
--home $HOME2 \
--proxy_app kvstore \
--p2p.laddr tcp://127.0.0.1:56666 \
--rpc.laddr tcp://127.0.0.1:56667 \
--p2p.persistent_peers 127.0.0.1:56656 \
--log_level error &
# wait for node to start up so we only count time where we are actually syncing
sleep 0.5
while curl localhost:56667/status 2> /dev/null | grep "\"latest_block_height\": 0," > /dev/null
do
printf '.'
sleep 0.2
done
echo
echo "syncing blockchain for 10s"
for i in {1..10}
do
sleep 1
HEIGHT="$(curl localhost:56667/status 2> /dev/null \
| grep 'latest_block_height' \
| grep -o ' [0-9]*' \
| xargs)"
let 'RATE = HEIGHT / i'
echo "height: $HEIGHT, blocks/sec: $RATE"
done
kill %1
kill %2
rm -rf $HOME1 $HOME2

View File

@ -2,37 +2,47 @@ package benchmarks
import (
"testing"
"time"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/go-crypto"
"github.com/tendermint/go-p2p"
"github.com/tendermint/go-wire"
proto "github.com/tendermint/tendermint/benchmarks/proto"
"github.com/tendermint/tendermint/p2p"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
func BenchmarkEncodeStatusWire(b *testing.B) {
b.StopTimer()
pubKey := crypto.GenPrivKeyEd25519().PubKey().(crypto.PubKeyEd25519)
cdc := amino.NewCodec()
ctypes.RegisterAmino(cdc)
nodeKey := p2p.NodeKey{PrivKey: crypto.GenPrivKeyEd25519()}
status := &ctypes.ResultStatus{
NodeInfo: &p2p.NodeInfo{
PubKey: pubKey,
NodeInfo: p2p.NodeInfo{
ID: nodeKey.ID(),
Moniker: "SOMENAME",
Network: "SOMENAME",
RemoteAddr: "SOMEADDR",
ListenAddr: "SOMEADDR",
Version: "SOMEVER",
Other: []string{"SOMESTRING", "OTHERSTRING"},
},
PubKey: pubKey,
LatestBlockHash: []byte("SOMEBYTES"),
LatestBlockHeight: 123,
LatestBlockTime: 1234,
SyncInfo: ctypes.SyncInfo{
LatestBlockHash: []byte("SOMEBYTES"),
LatestBlockHeight: 123,
LatestBlockTime: time.Unix(0, 1234),
},
ValidatorInfo: ctypes.ValidatorInfo{
PubKey: nodeKey.PubKey(),
},
}
b.StartTimer()
counter := 0
for i := 0; i < b.N; i++ {
jsonBytes := wire.JSONBytes(status)
jsonBytes, err := cdc.MarshalJSON(status)
if err != nil {
panic(err)
}
counter += len(jsonBytes)
}
@ -40,12 +50,13 @@ func BenchmarkEncodeStatusWire(b *testing.B) {
func BenchmarkEncodeNodeInfoWire(b *testing.B) {
b.StopTimer()
pubKey := crypto.GenPrivKeyEd25519().PubKey().(crypto.PubKeyEd25519)
nodeInfo := &p2p.NodeInfo{
PubKey: pubKey,
cdc := amino.NewCodec()
ctypes.RegisterAmino(cdc)
nodeKey := p2p.NodeKey{PrivKey: crypto.GenPrivKeyEd25519()}
nodeInfo := p2p.NodeInfo{
ID: nodeKey.ID(),
Moniker: "SOMENAME",
Network: "SOMENAME",
RemoteAddr: "SOMEADDR",
ListenAddr: "SOMEADDR",
Version: "SOMEVER",
Other: []string{"SOMESTRING", "OTHERSTRING"},
@ -54,19 +65,23 @@ func BenchmarkEncodeNodeInfoWire(b *testing.B) {
counter := 0
for i := 0; i < b.N; i++ {
jsonBytes := wire.JSONBytes(nodeInfo)
jsonBytes, err := cdc.MarshalJSON(nodeInfo)
if err != nil {
panic(err)
}
counter += len(jsonBytes)
}
}
func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
b.StopTimer()
pubKey := crypto.GenPrivKeyEd25519().PubKey().(crypto.PubKeyEd25519)
nodeInfo := &p2p.NodeInfo{
PubKey: pubKey,
cdc := amino.NewCodec()
ctypes.RegisterAmino(cdc)
nodeKey := p2p.NodeKey{PrivKey: crypto.GenPrivKeyEd25519()}
nodeInfo := p2p.NodeInfo{
ID: nodeKey.ID(),
Moniker: "SOMENAME",
Network: "SOMENAME",
RemoteAddr: "SOMEADDR",
ListenAddr: "SOMEADDR",
Version: "SOMEVER",
Other: []string{"SOMESTRING", "OTHERSTRING"},
@ -75,7 +90,7 @@ func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
counter := 0
for i := 0; i < b.N; i++ {
jsonBytes := wire.BinaryBytes(nodeInfo)
jsonBytes := cdc.MustMarshalBinaryBare(nodeInfo)
counter += len(jsonBytes)
}
@ -83,16 +98,20 @@ func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
func BenchmarkEncodeNodeInfoProto(b *testing.B) {
b.StopTimer()
pubKey := crypto.GenPrivKeyEd25519().PubKey().(crypto.PubKeyEd25519)
pubKey2 := &proto.PubKey{Ed25519: &proto.PubKeyEd25519{Bytes: pubKey[:]}}
nodeInfo := &proto.NodeInfo{
PubKey: pubKey2,
Moniker: "SOMENAME",
Network: "SOMENAME",
RemoteAddr: "SOMEADDR",
ListenAddr: "SOMEADDR",
Version: "SOMEVER",
Other: []string{"SOMESTRING", "OTHERSTRING"},
nodeKey := p2p.NodeKey{PrivKey: crypto.GenPrivKeyEd25519()}
nodeID := string(nodeKey.ID())
someName := "SOMENAME"
someAddr := "SOMEADDR"
someVer := "SOMEVER"
someString := "SOMESTRING"
otherString := "OTHERSTRING"
nodeInfo := proto.NodeInfo{
Id: &proto.ID{Id: &nodeID},
Moniker: &someName,
Network: &someName,
ListenAddr: &someAddr,
Version: &someVer,
Other: []string{someString, otherString},
}
b.StartTimer()

View File

@ -0,0 +1,26 @@
DIST_DIRS := find * -type d -exec
VERSION := $(shell perl -ne '/^var version.*"([^"]+)".*$$/ && print "v$$1\n"' main.go)
GOTOOLS = \
github.com/mitchellh/gox
tools:
go get $(GOTOOLS)
get_vendor_deps:
@hash glide 2>/dev/null || go get github.com/Masterminds/glide
glide install
build:
go build
install:
go install
test:
go test -race
clean:
rm -f ./experiments
rm -rf ./dist
.PHONY: tools get_vendor_deps build install test clean

View File

@ -0,0 +1,12 @@
package: github.com/tendermint/tendermint/benchmarks/experiments
import:
- package: github.com/tendermint/tendermint
version: v0.16.0
subpackages:
- rpc/client
- rpc/lib/types
- types
- package: github.com/tendermint/tmlibs
version: v0.7.0
subpackages:
- log

View File

@ -0,0 +1,126 @@
package main
import (
"encoding/binary"
"fmt"
"math/rand"
"os"
"sync"
"time"
"context"
"github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/log"
)
var logger = log.NewNopLogger()
var finishedTasks = 0
var mutex = &sync.Mutex{}
func main() {
var endpoint = "tcp://0.0.0.0:46657"
var httpClient = getHTTPClient(endpoint)
var res, err = httpClient.Status()
if err != nil {
logger.Info("something wrong happens", err)
}
logger.Info("received status", res)
go monitorTask(endpoint)
txCount := 10
var clientNumber = 10
for i := 0; i < clientNumber; i++ {
go clientTask(i, txCount, endpoint)
}
for finishedTasks < clientNumber+1 {
}
fmt.Printf("Done: %d\n", finishedTasks)
}
func clientTask(id, txCount int, endpoint string) {
var httpClient = getHTTPClient(endpoint)
for i := 0; i < txCount; i++ {
var _, err = httpClient.BroadcastTxSync(generateTx(id, rand.Int()))
if err != nil {
fmt.Printf("Something wrong happened: %s\n", err)
}
}
fmt.Printf("Finished client task: %d\n", id)
mutex.Lock()
finishedTasks++
mutex.Unlock()
}
func getHTTPClient(rpcAddr string) *client.HTTP {
return client.NewHTTP(rpcAddr, "/websocket")
}
func generateTx(i, valI int) []byte {
// a tx encodes the validator index, the tx number, and some random junk
tx := make([]byte, 250)
binary.PutUvarint(tx[:32], uint64(valI))
binary.PutUvarint(tx[32:64], uint64(i))
if _, err := rand.Read(tx[65:]); err != nil {
fmt.Println("err reading from crypto/rand", err)
os.Exit(1)
}
return tx
}
func monitorTask(endpoint string) {
fmt.Println("Monitor task started...")
var duration = 5 * time.Second
const subscriber = "monitor"
ctx, cancel := context.WithTimeout(context.Background(), duration)
defer cancel()
evts := make(chan interface{})
var httpClient = getHTTPClient(endpoint)
httpClient.Start()
evtTyp := types.EventNewBlockHeader
// register for the next event of this type
query := types.QueryForEvent(evtTyp)
err := httpClient.Subscribe(ctx, subscriber, query, evts)
if err != nil {
fmt.Println("error when subscribing", err)
}
// make sure to unregister after the test is over
defer httpClient.UnsubscribeAll(ctx, subscriber)
totalNumOfCommittedTxs := int64(0)
for {
fmt.Println("Starting main loop", err)
select {
case evt := <-evts:
event := evt.(types.TMEventData)
header, ok := event.Unwrap().(types.EventDataNewBlockHeader)
if ok {
fmt.Println("received header\n", header.Header.StringIndented(""))
} else {
fmt.Println("not able to unwrap header")
}
// Do some metric computation with header
totalNumOfCommittedTxs += header.Header.NumTxs
case <-ctx.Done():
fmt.Printf("Finished monitor task. Received %d transactions \n", totalNumOfCommittedTxs)
mutex.Lock()
finishedTasks++
mutex.Unlock()
return
}
}
}

View File

@ -1,8 +1,9 @@
package benchmarks
import (
. "github.com/tendermint/go-common"
"testing"
cmn "github.com/tendermint/tmlibs/common"
)
func BenchmarkSomething(b *testing.B) {
@ -11,11 +12,11 @@ func BenchmarkSomething(b *testing.B) {
numChecks := 100000
keys := make([]string, numItems)
for i := 0; i < numItems; i++ {
keys[i] = RandStr(100)
keys[i] = cmn.RandStr(100)
}
txs := make([]string, numChecks)
for i := 0; i < numChecks; i++ {
txs[i] = RandStr(100)
txs[i] = cmn.RandStr(100)
}
b.StartTimer()

View File

@ -4,7 +4,7 @@ import (
"os"
"testing"
. "github.com/tendermint/go-common"
cmn "github.com/tendermint/tmlibs/common"
)
func BenchmarkFileWrite(b *testing.B) {
@ -14,16 +14,20 @@ func BenchmarkFileWrite(b *testing.B) {
if err != nil {
b.Error(err)
}
testString := RandStr(200) + "\n"
testString := cmn.RandStr(200) + "\n"
b.StartTimer()
for i := 0; i < b.N; i++ {
file.Write([]byte(testString))
_, err := file.Write([]byte(testString))
if err != nil {
b.Error(err)
}
}
file.Close()
err = os.Remove("benchmark_file_write.out")
if err != nil {
if err := file.Close(); err != nil {
b.Error(err)
}
if err := os.Remove("benchmark_file_write.out"); err != nil {
b.Error(err)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ message ResultStatus {
}
message NodeInfo {
required PubKey pubKey = 1;
required ID id = 1;
required string moniker = 2;
required string network = 3;
required string remoteAddr = 4;
@ -16,6 +16,10 @@ message NodeInfo {
repeated string other = 7;
}
message ID {
required string id = 1;
}
message PubKey {
optional PubKeyEd25519 ed25519 = 1;
}

View File

@ -1,30 +1,27 @@
package main
import (
"context"
"encoding/binary"
"time"
//"encoding/hex"
"fmt"
"time"
"github.com/gorilla/websocket"
. "github.com/tendermint/go-common"
"github.com/tendermint/go-rpc/client"
"github.com/tendermint/go-rpc/types"
"github.com/tendermint/go-wire"
_ "github.com/tendermint/tendermint/rpc/core/types" // Register RPCResponse > Result types
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
cmn "github.com/tendermint/tmlibs/common"
)
func main() {
ws := rpcclient.NewWSClient("127.0.0.1:46657", "/websocket")
_, err := ws.Start()
wsc := rpcclient.NewWSClient("127.0.0.1:46657", "/websocket")
err := wsc.Start()
if err != nil {
Exit(err.Error())
cmn.Exit(err.Error())
}
defer wsc.Stop()
// Read a bunch of responses
go func() {
for {
_, ok := <-ws.ResultsCh
_, ok := <-wsc.ResponsesCh
if !ok {
break
}
@ -37,21 +34,14 @@ func main() {
for i := 0; ; i++ {
binary.BigEndian.PutUint64(buf, uint64(i))
//txBytes := hex.EncodeToString(buf[:n])
request := rpctypes.NewRPCRequest("fakeid",
"broadcast_tx",
map[string]interface{}{"tx": buf[:8]})
reqBytes := wire.JSONBytes(request)
//fmt.Println("!!", string(reqBytes))
fmt.Print(".")
err := ws.WriteMessage(websocket.TextMessage, reqBytes)
err = wsc.Call(context.TODO(), "broadcast_tx", map[string]interface{}{"tx": buf[:8]})
if err != nil {
Exit(err.Error())
cmn.Exit(err.Error())
}
if i%1000 == 0 {
fmt.Println(i)
}
time.Sleep(time.Microsecond * 1000)
}
ws.Stop()
}

View File

@ -1,7 +0,0 @@
package blockchain
import (
"github.com/tendermint/go-logger"
)
var log = logger.New("module", "blockchain")

View File

@ -1,24 +1,51 @@
package blockchain
import (
"errors"
"fmt"
"math"
"sync"
"time"
. "github.com/tendermint/go-common"
flow "github.com/tendermint/go-flowrate/flowrate"
cmn "github.com/tendermint/tmlibs/common"
flow "github.com/tendermint/tmlibs/flowrate"
"github.com/tendermint/tmlibs/log"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
/*
eg, L = latency = 0.1s
P = num peers = 10
FN = num full nodes
BS = 1kB block size
CB = 1 Mbit/s = 128 kB/s
CB/P = 12.8 kB
B/S = CB/P/BS = 12.8 blocks/s
12.8 * 0.1 = 1.28 blocks on conn
*/
const (
requestIntervalMS = 250
maxTotalRequesters = 300
requestIntervalMS = 100
maxTotalRequesters = 1000
maxPendingRequests = maxTotalRequesters
maxPendingRequestsPerPeer = 75
minRecvRate = 10240 // 10Kb/s
maxPendingRequestsPerPeer = 50
// Minimum recv rate to ensure we're receiving blocks from a peer fast
// enough. If a peer is not sending us data at at least that rate, we
// consider them to have timedout and we disconnect.
//
// Assuming a DSL connection (not a good choice) 128 Kbps (upload) ~ 15 KB/s,
// sending data across atlantic ~ 7.5 KB/s.
minRecvRate = 7680
// Maximum difference between current and new block's height.
maxDiffBetweenCurrentAndReceivedBlockHeight = 100
)
var peerTimeoutSeconds = time.Duration(15) // not const so we can override with tests
var peerTimeout = 15 * time.Second // not const so we can override with tests
/*
Peers self report their heights when we join the block pool.
@ -27,38 +54,39 @@ var peerTimeoutSeconds = time.Duration(15) // not const so we can override with
Every so often we ask peers what height they're on so we can keep going.
Requests are continuously made for blocks of higher heights until
the limits. If most of the requests have no available peers, and we
the limit is reached. If most of the requests have no available peers, and we
are not at peer limits, we can probably switch to consensus reactor
*/
type BlockPool struct {
BaseService
cmn.BaseService
startTime time.Time
mtx sync.Mutex
// block requests
requesters map[int]*bpRequester
height int // the lowest key in requesters.
requesters map[int64]*bpRequester
height int64 // the lowest key in requesters.
numPending int32 // number of requests pending assignment or block response
// peers
peers map[string]*bpPeer
peers map[p2p.ID]*bpPeer
maxPeerHeight int64
requestsCh chan<- BlockRequest
timeoutsCh chan<- string
errorsCh chan<- peerError
}
func NewBlockPool(start int, requestsCh chan<- BlockRequest, timeoutsCh chan<- string) *BlockPool {
func NewBlockPool(start int64, requestsCh chan<- BlockRequest, errorsCh chan<- peerError) *BlockPool {
bp := &BlockPool{
peers: make(map[string]*bpPeer),
peers: make(map[p2p.ID]*bpPeer),
requesters: make(map[int]*bpRequester),
requesters: make(map[int64]*bpRequester),
height: start,
numPending: 0,
requestsCh: requestsCh,
timeoutsCh: timeoutsCh,
errorsCh: errorsCh,
}
bp.BaseService = *NewBaseService(log, "BlockPool", bp)
bp.BaseService = *cmn.NewBaseService(nil, "BlockPool", bp)
return bp
}
@ -68,9 +96,7 @@ func (pool *BlockPool) OnStart() error {
return nil
}
func (pool *BlockPool) OnStop() {
pool.BaseService.OnStop()
}
func (pool *BlockPool) OnStop() {}
// Run spawns requesters as needed.
func (pool *BlockPool) makeRequestersRoutine() {
@ -78,6 +104,7 @@ func (pool *BlockPool) makeRequestersRoutine() {
if !pool.IsRunning() {
break
}
_, numPending, lenRequesters := pool.GetStatus()
if numPending >= maxPendingRequests {
// sleep for a bit.
@ -103,10 +130,14 @@ func (pool *BlockPool) removeTimedoutPeers() {
for _, peer := range pool.peers {
if !peer.didTimeout && peer.numPending > 0 {
curRate := peer.recvMonitor.Status().CurRate
// XXX remove curRate != 0
// curRate can be 0 on start
if curRate != 0 && curRate < minRecvRate {
pool.sendTimeout(peer.id)
log.Warn("SendTimeout", "peer", peer.id, "reason", "curRate too low")
err := errors.New("peer is not sending us data fast enough")
pool.sendError(err, peer.id)
pool.Logger.Error("SendTimeout", "peer", peer.id,
"reason", err,
"curRate", fmt.Sprintf("%d KB/s", curRate/1024),
"minRate", fmt.Sprintf("%d KB/s", minRecvRate/1024))
peer.didTimeout = true
}
}
@ -116,7 +147,7 @@ func (pool *BlockPool) removeTimedoutPeers() {
}
}
func (pool *BlockPool) GetStatus() (height int, numPending int32, lenRequesters int) {
func (pool *BlockPool) GetStatus() (height int64, numPending int32, lenRequesters int) {
pool.mtx.Lock()
defer pool.mtx.Unlock()
@ -128,21 +159,16 @@ func (pool *BlockPool) IsCaughtUp() bool {
pool.mtx.Lock()
defer pool.mtx.Unlock()
height := pool.height
// Need at least 1 peer to be considered caught up.
if len(pool.peers) == 0 {
log.Debug("Blockpool has no peers")
pool.Logger.Debug("Blockpool has no peers")
return false
}
maxPeerHeight := 0
for _, peer := range pool.peers {
maxPeerHeight = MaxInt(maxPeerHeight, peer.height)
}
isCaughtUp := (height > 0 || time.Now().Sub(pool.startTime) > 5*time.Second) && (maxPeerHeight == 0 || height >= maxPeerHeight)
log.Notice(Fmt("IsCaughtUp: %v", isCaughtUp), "height", height, "maxPeerHeight", maxPeerHeight)
// some conditions to determine if we're caught up
receivedBlockOrTimedOut := (pool.height > 0 || time.Since(pool.startTime) > 5*time.Second)
ourChainIsLongestAmongPeers := pool.maxPeerHeight == 0 || pool.height >= pool.maxPeerHeight
isCaughtUp := receivedBlockOrTimedOut && ourChainIsLongestAmongPeers
return isCaughtUp
}
@ -178,46 +204,66 @@ func (pool *BlockPool) PopRequest() {
delete(pool.requesters, pool.height)
pool.height++
} else {
PanicSanity(Fmt("Expected requester to pop, got nothing at height %v", pool.height))
panic(fmt.Sprintf("Expected requester to pop, got nothing at height %v", pool.height))
}
}
// Invalidates the block at pool.height,
// Remove the peer and redo request from others.
func (pool *BlockPool) RedoRequest(height int) {
// Returns the ID of the removed peer.
func (pool *BlockPool) RedoRequest(height int64) p2p.ID {
pool.mtx.Lock()
defer pool.mtx.Unlock()
request := pool.requesters[height]
pool.mtx.Unlock()
if request.block == nil {
PanicSanity("Expected block to be non-nil")
panic("Expected block to be non-nil")
}
// RemovePeer will redo all requesters associated with this peer.
// TODO: record this malfeasance
pool.RemovePeer(request.peerID)
pool.removePeer(request.peerID)
return request.peerID
}
// TODO: ensure that blocks come in order for each peer.
func (pool *BlockPool) AddBlock(peerID string, block *types.Block, blockSize int) {
func (pool *BlockPool) AddBlock(peerID p2p.ID, block *types.Block, blockSize int) {
pool.mtx.Lock()
defer pool.mtx.Unlock()
requester := pool.requesters[block.Height]
if requester == nil {
pool.Logger.Info("peer sent us a block we didn't expect", "peer", peerID, "curHeight", pool.height, "blockHeight", block.Height)
diff := pool.height - block.Height
if diff < 0 {
diff *= -1
}
if diff > maxDiffBetweenCurrentAndReceivedBlockHeight {
pool.sendError(errors.New("peer sent us a block we didn't expect with a height too far ahead/behind"), peerID)
}
return
}
if requester.setBlock(block, peerID) {
pool.numPending--
peer := pool.peers[peerID]
peer.decrPending(blockSize)
if peer != nil {
peer.decrPending(blockSize)
}
} else {
// Bad peer?
}
}
// MaxPeerHeight returns the highest height reported by a peer.
func (pool *BlockPool) MaxPeerHeight() int64 {
pool.mtx.Lock()
defer pool.mtx.Unlock()
return pool.maxPeerHeight
}
// Sets the peer's alleged blockchain height.
func (pool *BlockPool) SetPeerHeight(peerID string, height int) {
func (pool *BlockPool) SetPeerHeight(peerID p2p.ID, height int64) {
pool.mtx.Lock()
defer pool.mtx.Unlock()
@ -226,18 +272,23 @@ func (pool *BlockPool) SetPeerHeight(peerID string, height int) {
peer.height = height
} else {
peer = newBPPeer(pool, peerID, height)
peer.setLogger(pool.Logger.With("peer", peerID))
pool.peers[peerID] = peer
}
if height > pool.maxPeerHeight {
pool.maxPeerHeight = height
}
}
func (pool *BlockPool) RemovePeer(peerID string) {
func (pool *BlockPool) RemovePeer(peerID p2p.ID) {
pool.mtx.Lock()
defer pool.mtx.Unlock()
pool.removePeer(peerID)
}
func (pool *BlockPool) removePeer(peerID string) {
func (pool *BlockPool) removePeer(peerID p2p.ID) {
for _, requester := range pool.requesters {
if requester.getPeerID() == peerID {
if requester.getBlock() != nil {
@ -251,7 +302,7 @@ func (pool *BlockPool) removePeer(peerID string) {
// Pick an available peer with at least the given minHeight.
// If no peers are available, returns nil.
func (pool *BlockPool) pickIncrAvailablePeer(minHeight int) *bpPeer {
func (pool *BlockPool) pickIncrAvailablePeer(minHeight int64) *bpPeer {
pool.mtx.Lock()
defer pool.mtx.Unlock()
@ -259,7 +310,6 @@ func (pool *BlockPool) pickIncrAvailablePeer(minHeight int) *bpPeer {
if peer.didTimeout {
pool.removePeer(peer.id)
continue
} else {
}
if peer.numPending >= maxPendingRequestsPerPeer {
continue
@ -277,40 +327,50 @@ func (pool *BlockPool) makeNextRequester() {
pool.mtx.Lock()
defer pool.mtx.Unlock()
nextHeight := pool.height + len(pool.requesters)
nextHeight := pool.height + pool.requestersLen()
request := newBPRequester(pool, nextHeight)
// request.SetLogger(pool.Logger.With("height", nextHeight))
pool.requesters[nextHeight] = request
pool.numPending++
request.Start()
err := request.Start()
if err != nil {
request.Logger.Error("Error starting request", "err", err)
}
}
func (pool *BlockPool) sendRequest(height int, peerID string) {
func (pool *BlockPool) requestersLen() int64 {
return int64(len(pool.requesters))
}
func (pool *BlockPool) sendRequest(height int64, peerID p2p.ID) {
if !pool.IsRunning() {
return
}
pool.requestsCh <- BlockRequest{height, peerID}
}
func (pool *BlockPool) sendTimeout(peerID string) {
func (pool *BlockPool) sendError(err error, peerID p2p.ID) {
if !pool.IsRunning() {
return
}
pool.timeoutsCh <- peerID
pool.errorsCh <- peerError{err, peerID}
}
// unused by tendermint; left for debugging purposes
func (pool *BlockPool) debug() string {
pool.mtx.Lock() // Lock
defer pool.mtx.Unlock()
str := ""
for h := pool.height; h < pool.height+len(pool.requesters); h++ {
nextHeight := pool.height + pool.requestersLen()
for h := pool.height; h < nextHeight; h++ {
if pool.requesters[h] == nil {
str += Fmt("H(%v):X ", h)
str += cmn.Fmt("H(%v):X ", h)
} else {
str += Fmt("H(%v):", h)
str += Fmt("B?(%v) ", pool.requesters[h].block != nil)
str += cmn.Fmt("H(%v):", h)
str += cmn.Fmt("B?(%v) ", pool.requesters[h].block != nil)
}
}
return str
@ -320,37 +380,43 @@ func (pool *BlockPool) debug() string {
type bpPeer struct {
pool *BlockPool
id string
id p2p.ID
recvMonitor *flow.Monitor
mtx sync.Mutex
height int
height int64
numPending int32
timeout *time.Timer
didTimeout bool
logger log.Logger
}
func newBPPeer(pool *BlockPool, peerID string, height int) *bpPeer {
func newBPPeer(pool *BlockPool, peerID p2p.ID, height int64) *bpPeer {
peer := &bpPeer{
pool: pool,
id: peerID,
height: height,
numPending: 0,
logger: log.NewNopLogger(),
}
return peer
}
func (peer *bpPeer) setLogger(l log.Logger) {
peer.logger = l
}
func (peer *bpPeer) resetMonitor() {
peer.recvMonitor = flow.New(time.Second, time.Second*40)
var initialValue = float64(minRecvRate) * math.E
initialValue := float64(minRecvRate) * math.E
peer.recvMonitor.SetREMA(initialValue)
}
func (peer *bpPeer) resetTimeout() {
if peer.timeout == nil {
peer.timeout = time.AfterFunc(time.Second*peerTimeoutSeconds, peer.onTimeout)
peer.timeout = time.AfterFunc(peerTimeout, peer.onTimeout)
} else {
peer.timeout.Reset(time.Second * peerTimeoutSeconds)
peer.timeout.Reset(peerTimeout)
}
}
@ -376,26 +442,27 @@ func (peer *bpPeer) onTimeout() {
peer.pool.mtx.Lock()
defer peer.pool.mtx.Unlock()
peer.pool.sendTimeout(peer.id)
log.Warn("SendTimeout", "peer", peer.id, "reason", "onTimeout")
err := errors.New("peer did not send us anything")
peer.pool.sendError(err, peer.id)
peer.logger.Error("SendTimeout", "reason", err, "timeout", peerTimeout)
peer.didTimeout = true
}
//-------------------------------------
type bpRequester struct {
BaseService
cmn.BaseService
pool *BlockPool
height int
height int64
gotBlockCh chan struct{}
redoCh chan struct{}
mtx sync.Mutex
peerID string
peerID p2p.ID
block *types.Block
}
func newBPRequester(pool *BlockPool, height int) *bpRequester {
func newBPRequester(pool *BlockPool, height int64) *bpRequester {
bpr := &bpRequester{
pool: pool,
height: height,
@ -405,7 +472,7 @@ func newBPRequester(pool *BlockPool, height int) *bpRequester {
peerID: "",
block: nil,
}
bpr.BaseService = *NewBaseService(nil, "bpRequester", bpr)
bpr.BaseService = *cmn.NewBaseService(nil, "bpRequester", bpr)
return bpr
}
@ -415,7 +482,7 @@ func (bpr *bpRequester) OnStart() error {
}
// Returns true if the peer matches
func (bpr *bpRequester) setBlock(block *types.Block, peerID string) bool {
func (bpr *bpRequester) setBlock(block *types.Block, peerID p2p.ID) bool {
bpr.mtx.Lock()
if bpr.block != nil || bpr.peerID != peerID {
bpr.mtx.Unlock()
@ -434,7 +501,7 @@ func (bpr *bpRequester) getBlock() *types.Block {
return bpr.block
}
func (bpr *bpRequester) getPeerID() string {
func (bpr *bpRequester) getPeerID() p2p.ID {
bpr.mtx.Lock()
defer bpr.mtx.Unlock()
return bpr.peerID
@ -459,7 +526,7 @@ func (bpr *bpRequester) requestRoutine() {
OUTER_LOOP:
for {
// Pick a peer to send request to.
var peer *bpPeer = nil
var peer *bpPeer
PICK_PEER_LOOP:
for {
if !bpr.IsRunning() || !bpr.pool.IsRunning() {
@ -480,10 +547,10 @@ OUTER_LOOP:
// Send request and wait.
bpr.pool.sendRequest(bpr.height, peer.id)
select {
case <-bpr.pool.Quit:
case <-bpr.pool.Quit():
bpr.Stop()
return
case <-bpr.Quit:
case <-bpr.Quit():
return
case <-bpr.redoCh:
bpr.reset()
@ -491,10 +558,10 @@ OUTER_LOOP:
case <-bpr.gotBlockCh:
// We got the block, now see if it's good.
select {
case <-bpr.pool.Quit:
case <-bpr.pool.Quit():
bpr.Stop()
return
case <-bpr.Quit:
case <-bpr.Quit():
return
case <-bpr.redoCh:
bpr.reset()
@ -507,6 +574,6 @@ OUTER_LOOP:
//-------------------------------------
type BlockRequest struct {
Height int
PeerID string
Height int64
PeerID p2p.ID
}

View File

@ -5,36 +5,45 @@ import (
"testing"
"time"
. "github.com/tendermint/go-common"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
)
func init() {
peerTimeoutSeconds = time.Duration(2)
peerTimeout = 2 * time.Second
}
type testPeer struct {
id string
height int
id p2p.ID
height int64
}
func makePeers(numPeers int, minHeight, maxHeight int) map[string]testPeer {
peers := make(map[string]testPeer, numPeers)
func makePeers(numPeers int, minHeight, maxHeight int64) map[p2p.ID]testPeer {
peers := make(map[p2p.ID]testPeer, numPeers)
for i := 0; i < numPeers; i++ {
peerID := RandStr(12)
height := minHeight + rand.Intn(maxHeight-minHeight)
peerID := p2p.ID(cmn.RandStr(12))
height := minHeight + rand.Int63n(maxHeight-minHeight)
peers[peerID] = testPeer{peerID, height}
}
return peers
}
func TestBasic(t *testing.T) {
start := 42
start := int64(42)
peers := makePeers(10, start+1, 1000)
timeoutsCh := make(chan string, 100)
requestsCh := make(chan BlockRequest, 100)
pool := NewBlockPool(start, requestsCh, timeoutsCh)
pool.Start()
errorsCh := make(chan peerError, 1000)
requestsCh := make(chan BlockRequest, 1000)
pool := NewBlockPool(start, requestsCh, errorsCh)
pool.SetLogger(log.TestingLogger())
err := pool.Start()
if err != nil {
t.Error(err)
}
defer pool.Stop()
// Introduce each peer.
@ -62,10 +71,10 @@ func TestBasic(t *testing.T) {
// Pull from channels
for {
select {
case peerID := <-timeoutsCh:
t.Errorf("timeout: %v", peerID)
case err := <-errorsCh:
t.Error(err)
case request := <-requestsCh:
log.Info("TEST: Pulled new BlockRequest", "request", request)
t.Logf("Pulled new BlockRequest %v", request)
if request.Height == 300 {
return // Done!
}
@ -73,23 +82,27 @@ func TestBasic(t *testing.T) {
go func() {
block := &types.Block{Header: &types.Header{Height: request.Height}}
pool.AddBlock(request.PeerID, block, 123)
log.Info("TEST: Added block", "block", request.Height, "peer", request.PeerID)
t.Logf("Added block from peer %v (height: %v)", request.PeerID, request.Height)
}()
}
}
}
func TestTimeout(t *testing.T) {
start := 42
start := int64(42)
peers := makePeers(10, start+1, 1000)
timeoutsCh := make(chan string, 100)
requestsCh := make(chan BlockRequest, 100)
pool := NewBlockPool(start, requestsCh, timeoutsCh)
pool.Start()
errorsCh := make(chan peerError, 1000)
requestsCh := make(chan BlockRequest, 1000)
pool := NewBlockPool(start, requestsCh, errorsCh)
pool.SetLogger(log.TestingLogger())
err := pool.Start()
if err != nil {
t.Error(err)
}
defer pool.Stop()
for _, peer := range peers {
log.Info("Peer", "id", peer.id)
t.Logf("Peer %v", peer.id)
}
// Introduce each peer.
@ -116,19 +129,20 @@ func TestTimeout(t *testing.T) {
// Pull from channels
counter := 0
timedOut := map[string]struct{}{}
timedOut := map[p2p.ID]struct{}{}
for {
select {
case peerID := <-timeoutsCh:
log.Info("Timeout", "peerID", peerID)
if _, ok := timedOut[peerID]; !ok {
case err := <-errorsCh:
t.Log(err)
// consider error to be always timeout here
if _, ok := timedOut[err.peerID]; !ok {
counter++
if counter == len(peers) {
return // Done!
}
}
case request := <-requestsCh:
log.Info("TEST: Pulled new BlockRequest", "request", request)
t.Logf("Pulled new BlockRequest %+v", request)
}
}
}

View File

@ -1,27 +1,23 @@
package blockchain
import (
"bytes"
"errors"
"fmt"
"reflect"
"time"
cmn "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
"github.com/tendermint/go-p2p"
"github.com/tendermint/go-wire"
"github.com/tendermint/tendermint/proxy"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/p2p"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
)
const (
// BlockchainChannel is a channel for blocks and status updates (`BlockStore` height)
BlockchainChannel = byte(0x40)
defaultChannelCapacity = 100
defaultSleepIntervalMS = 500
trySyncIntervalMS = 100
trySyncIntervalMS = 50
// stop syncing when last block's time is
// within this much of the system time.
// stopSyncingDurationMinutes = 10
@ -30,66 +26,91 @@ const (
statusUpdateIntervalSeconds = 10
// check if we should switch to consensus reactor
switchToConsensusIntervalSeconds = 1
maxBlockchainResponseSize = types.MaxBlockSize + 2
// NOTE: keep up to date with bcBlockResponseMessage
bcBlockResponseMessagePrefixSize = 4
bcBlockResponseMessageFieldKeySize = 1
maxMsgSize = types.MaxBlockSizeBytes +
bcBlockResponseMessagePrefixSize +
bcBlockResponseMessageFieldKeySize
)
type consensusReactor interface {
// for when we switch from blockchain reactor and fast sync to
// the consensus machine
SwitchToConsensus(*sm.State)
SwitchToConsensus(sm.State, int)
}
type peerError struct {
err error
peerID p2p.ID
}
func (e peerError) Error() string {
return fmt.Sprintf("error with peer %v: %s", e.peerID, e.err.Error())
}
// BlockchainReactor handles long-term catchup syncing.
type BlockchainReactor struct {
p2p.BaseReactor
config cfg.Config
state *sm.State
proxyAppConn proxy.AppConnConsensus // same as consensus.proxyAppConn
store *BlockStore
pool *BlockPool
fastSync bool
requestsCh chan BlockRequest
timeoutsCh chan string
lastBlock *types.Block
// immutable
initialState sm.State
evsw types.EventSwitch
blockExec *sm.BlockExecutor
store *BlockStore
pool *BlockPool
fastSync bool
requestsCh <-chan BlockRequest
errorsCh <-chan peerError
}
// NewBlockchainReactor returns new reactor instance.
func NewBlockchainReactor(config cfg.Config, state *sm.State, proxyAppConn proxy.AppConnConsensus, store *BlockStore, fastSync bool) *BlockchainReactor {
if state.LastBlockHeight == store.Height()-1 {
store.height-- // XXX HACK, make this better
}
func NewBlockchainReactor(state sm.State, blockExec *sm.BlockExecutor, store *BlockStore,
fastSync bool) *BlockchainReactor {
if state.LastBlockHeight != store.Height() {
cmn.PanicSanity(cmn.Fmt("state (%v) and store (%v) height mismatch", state.LastBlockHeight, store.Height()))
panic(fmt.Sprintf("state (%v) and store (%v) height mismatch", state.LastBlockHeight,
store.Height()))
}
requestsCh := make(chan BlockRequest, defaultChannelCapacity)
timeoutsCh := make(chan string, defaultChannelCapacity)
const capacity = 1000 // must be bigger than peers count
requestsCh := make(chan BlockRequest, capacity)
errorsCh := make(chan peerError, capacity) // so we don't block in #Receive#pool.AddBlock
pool := NewBlockPool(
store.Height()+1,
requestsCh,
timeoutsCh,
errorsCh,
)
bcR := &BlockchainReactor{
config: config,
state: state,
proxyAppConn: proxyAppConn,
initialState: state,
blockExec: blockExec,
store: store,
pool: pool,
fastSync: fastSync,
requestsCh: requestsCh,
timeoutsCh: timeoutsCh,
errorsCh: errorsCh,
}
bcR.BaseReactor = *p2p.NewBaseReactor(log, "BlockchainReactor", bcR)
bcR.BaseReactor = *p2p.NewBaseReactor("BlockchainReactor", bcR)
return bcR
}
// OnStart implements BaseService
// SetLogger implements cmn.Service by setting the logger on reactor and pool.
func (bcR *BlockchainReactor) SetLogger(l log.Logger) {
bcR.BaseService.Logger = l
bcR.pool.Logger = l
}
// OnStart implements cmn.Service.
func (bcR *BlockchainReactor) OnStart() error {
bcR.BaseReactor.OnStart()
if err := bcR.BaseReactor.OnStart(); err != nil {
return err
}
if bcR.fastSync {
_, err := bcR.pool.Start()
err := bcR.pool.Start()
if err != nil {
return err
}
@ -98,7 +119,7 @@ func (bcR *BlockchainReactor) OnStart() error {
return nil
}
// OnStop implements BaseService
// OnStop implements cmn.Service.
func (bcR *BlockchainReactor) OnStop() {
bcR.BaseReactor.OnStop()
bcR.pool.Stop()
@ -107,63 +128,81 @@ func (bcR *BlockchainReactor) OnStop() {
// GetChannels implements Reactor
func (bcR *BlockchainReactor) GetChannels() []*p2p.ChannelDescriptor {
return []*p2p.ChannelDescriptor{
&p2p.ChannelDescriptor{
ID: BlockchainChannel,
Priority: 5,
SendQueueCapacity: 100,
{
ID: BlockchainChannel,
Priority: 10,
SendQueueCapacity: 1000,
RecvBufferCapacity: 50 * 4096,
RecvMessageCapacity: maxMsgSize,
},
}
}
// AddPeer implements Reactor by sending our state to peer.
func (bcR *BlockchainReactor) AddPeer(peer *p2p.Peer) {
if !peer.Send(BlockchainChannel, struct{ BlockchainMessage }{&bcStatusResponseMessage{bcR.store.Height()}}) {
func (bcR *BlockchainReactor) AddPeer(peer p2p.Peer) {
msgBytes := cdc.MustMarshalBinaryBare(&bcStatusResponseMessage{bcR.store.Height()})
if !peer.Send(BlockchainChannel, msgBytes) {
// doing nothing, will try later in `poolRoutine`
}
// peer is added to the pool once we receive the first
// bcStatusResponseMessage from the peer and call pool.SetPeerHeight
}
// RemovePeer implements Reactor by removing peer from the pool.
func (bcR *BlockchainReactor) RemovePeer(peer *p2p.Peer, reason interface{}) {
bcR.pool.RemovePeer(peer.Key)
func (bcR *BlockchainReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
bcR.pool.RemovePeer(peer.ID())
}
// respondToPeer loads a block and sends it to the requesting peer,
// if we have it. Otherwise, we'll respond saying we don't have it.
// According to the Tendermint spec, if all nodes are honest,
// no node should be requesting for a block that's non-existent.
func (bcR *BlockchainReactor) respondToPeer(msg *bcBlockRequestMessage,
src p2p.Peer) (queued bool) {
block := bcR.store.LoadBlock(msg.Height)
if block != nil {
msgBytes := cdc.MustMarshalBinaryBare(&bcBlockResponseMessage{Block: block})
return src.TrySend(BlockchainChannel, msgBytes)
}
bcR.Logger.Info("Peer asking for a block we don't have", "src", src, "height", msg.Height)
msgBytes := cdc.MustMarshalBinaryBare(&bcNoBlockResponseMessage{Height: msg.Height})
return src.TrySend(BlockchainChannel, msgBytes)
}
// Receive implements Reactor by handling 4 types of messages (look below).
func (bcR *BlockchainReactor) Receive(chID byte, src *p2p.Peer, msgBytes []byte) {
_, msg, err := DecodeMessage(msgBytes)
func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
msg, err := DecodeMessage(msgBytes)
if err != nil {
log.Warn("Error decoding message", "error", err)
bcR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
bcR.Switch.StopPeerForError(src, err)
return
}
log.Debug("Receive", "src", src, "chID", chID, "msg", msg)
bcR.Logger.Debug("Receive", "src", src, "chID", chID, "msg", msg)
switch msg := msg.(type) {
case *bcBlockRequestMessage:
// Got a request for a block. Respond with block if we have it.
block := bcR.store.LoadBlock(msg.Height)
if block != nil {
msg := &bcBlockResponseMessage{Block: block}
queued := src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg})
if !queued {
// queue is full, just ignore.
}
} else {
// TODO peer is asking for things we don't have.
if queued := bcR.respondToPeer(msg, src); !queued {
// Unfortunately not queued since the queue is full.
}
case *bcBlockResponseMessage:
// Got a block.
bcR.pool.AddBlock(src.Key, msg.Block, len(msgBytes))
bcR.pool.AddBlock(src.ID(), msg.Block, len(msgBytes))
case *bcStatusRequestMessage:
// Send peer our state.
queued := src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{&bcStatusResponseMessage{bcR.store.Height()}})
msgBytes := cdc.MustMarshalBinaryBare(&bcStatusResponseMessage{bcR.store.Height()})
queued := src.TrySend(BlockchainChannel, msgBytes)
if !queued {
// sorry
}
case *bcStatusResponseMessage:
// Got a peer status. Unverified.
bcR.pool.SetPeerHeight(src.Key, msg.Height)
bcR.pool.SetPeerHeight(src.ID(), msg.Height)
default:
log.Warn(cmn.Fmt("Unknown message type %v", reflect.TypeOf(msg)))
bcR.Logger.Error(cmn.Fmt("Unknown message type %v", reflect.TypeOf(msg)))
}
}
@ -176,85 +215,106 @@ func (bcR *BlockchainReactor) poolRoutine() {
statusUpdateTicker := time.NewTicker(statusUpdateIntervalSeconds * time.Second)
switchToConsensusTicker := time.NewTicker(switchToConsensusIntervalSeconds * time.Second)
blocksSynced := 0
chainID := bcR.initialState.ChainID
state := bcR.initialState
lastHundred := time.Now()
lastRate := 0.0
FOR_LOOP:
for {
select {
case request := <-bcR.requestsCh: // chan BlockRequest
case request := <-bcR.requestsCh:
peer := bcR.Switch.Peers().Get(request.PeerID)
if peer == nil {
continue FOR_LOOP // Peer has since been disconnected.
}
msg := &bcBlockRequestMessage{request.Height}
queued := peer.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg})
msgBytes := cdc.MustMarshalBinaryBare(&bcBlockRequestMessage{request.Height})
queued := peer.TrySend(BlockchainChannel, msgBytes)
if !queued {
// We couldn't make the request, send-queue full.
// The pool handles timeouts, just let it go.
continue FOR_LOOP
}
case peerID := <-bcR.timeoutsCh: // chan string
// Peer timed out.
peer := bcR.Switch.Peers().Get(peerID)
case err := <-bcR.errorsCh:
peer := bcR.Switch.Peers().Get(err.peerID)
if peer != nil {
bcR.Switch.StopPeerForError(peer, errors.New("BlockchainReactor Timeout"))
bcR.Switch.StopPeerForError(peer, err)
}
case _ = <-statusUpdateTicker.C:
case <-statusUpdateTicker.C:
// ask for status updates
go bcR.BroadcastStatusRequest()
case _ = <-switchToConsensusTicker.C:
height, numPending, _ := bcR.pool.GetStatus()
go bcR.BroadcastStatusRequest() // nolint: errcheck
case <-switchToConsensusTicker.C:
height, numPending, lenRequesters := bcR.pool.GetStatus()
outbound, inbound, _ := bcR.Switch.NumPeers()
log.Info("Consensus ticker", "numPending", numPending, "total", len(bcR.pool.requesters),
bcR.Logger.Debug("Consensus ticker", "numPending", numPending, "total", lenRequesters,
"outbound", outbound, "inbound", inbound)
if bcR.pool.IsCaughtUp() {
log.Notice("Time to switch to consensus reactor!", "height", height)
bcR.Logger.Info("Time to switch to consensus reactor!", "height", height)
bcR.pool.Stop()
conR := bcR.Switch.Reactor("CONSENSUS").(consensusReactor)
conR.SwitchToConsensus(bcR.state)
conR.SwitchToConsensus(state, blocksSynced)
break FOR_LOOP
}
case _ = <-trySyncTicker.C: // chan time
case <-trySyncTicker.C: // chan time
// This loop can be slow as long as it's doing syncing work.
SYNC_LOOP:
for i := 0; i < 10; i++ {
// See if there are any blocks to sync.
first, second := bcR.pool.PeekTwoBlocks()
//log.Info("TrySync peeked", "first", first, "second", second)
//bcR.Logger.Info("TrySync peeked", "first", first, "second", second)
if first == nil || second == nil {
// We need both to sync the first block.
break SYNC_LOOP
}
firstParts := first.MakePartSet(bcR.config.GetInt("block_part_size")) // TODO: put part size in parts header?
firstParts := first.MakePartSet(state.ConsensusParams.BlockPartSizeBytes)
firstPartsHeader := firstParts.Header()
firstID := types.BlockID{first.Hash(), firstPartsHeader}
// Finally, verify the first block using the second's commit
// NOTE: we can probably make this more efficient, but note that calling
// first.Hash() doesn't verify the tx contents, so MakePartSet() is
// currently necessary.
err := bcR.state.Validators.VerifyCommit(
bcR.state.ChainID, types.BlockID{first.Hash(), firstPartsHeader}, first.Height, second.LastCommit)
err := state.Validators.VerifyCommit(
chainID, firstID, first.Height, second.LastCommit)
if err != nil {
log.Info("error in validation", "error", err)
bcR.pool.RedoRequest(first.Height)
bcR.Logger.Error("Error in validation", "err", err)
peerID := bcR.pool.RedoRequest(first.Height)
peer := bcR.Switch.Peers().Get(peerID)
if peer != nil {
bcR.Switch.StopPeerForError(peer, fmt.Errorf("BlockchainReactor validation error: %v", err))
}
break SYNC_LOOP
} else {
bcR.pool.PopRequest()
// TODO: batch saves so we dont persist to disk every block
bcR.store.SaveBlock(first, firstParts, second.LastCommit)
// TODO: should we be firing events? need to fire NewBlock events manually ...
// NOTE: we could improve performance if we
// didn't make the app commit to disk every block
// ... but we would need a way to get the hash without it persisting
err := bcR.state.ApplyBlock(bcR.evsw, bcR.proxyAppConn, first, firstPartsHeader, types.MockMempool{})
// TODO: same thing for app - but we would need a way to
// get the hash without persisting the state
var err error
state, err = bcR.blockExec.ApplyBlock(state, firstID, first)
if err != nil {
// TODO This is bad, are we zombie?
cmn.PanicQ(cmn.Fmt("Failed to process committed block (%d:%X): %v", first.Height, first.Hash(), err))
cmn.PanicQ(cmn.Fmt("Failed to process committed block (%d:%X): %v",
first.Height, first.Hash(), err))
}
blocksSynced++
if blocksSynced%100 == 0 {
lastRate = 0.9*lastRate + 0.1*(100/time.Since(lastHundred).Seconds())
bcR.Logger.Info("Fast Sync Rate", "height", bcR.pool.height,
"max_peer_height", bcR.pool.MaxPeerHeight(), "blocks/s", lastRate)
lastHundred = time.Now()
}
}
}
continue FOR_LOOP
case <-bcR.Quit:
case <-bcR.Quit():
break FOR_LOOP
}
}
@ -262,45 +322,36 @@ FOR_LOOP:
// BroadcastStatusRequest broadcasts `BlockStore` height.
func (bcR *BlockchainReactor) BroadcastStatusRequest() error {
bcR.Switch.Broadcast(BlockchainChannel, struct{ BlockchainMessage }{&bcStatusRequestMessage{bcR.store.Height()}})
msgBytes := cdc.MustMarshalBinaryBare(&bcStatusRequestMessage{bcR.store.Height()})
bcR.Switch.Broadcast(BlockchainChannel, msgBytes)
return nil
}
// SetEventSwitch implements events.Eventable
func (bcR *BlockchainReactor) SetEventSwitch(evsw types.EventSwitch) {
bcR.evsw = evsw
}
//-----------------------------------------------------------------------------
// Messages
const (
msgTypeBlockRequest = byte(0x10)
msgTypeBlockResponse = byte(0x11)
msgTypeStatusResponse = byte(0x20)
msgTypeStatusRequest = byte(0x21)
)
// BlockchainMessage is a generic message for this reactor.
type BlockchainMessage interface{}
var _ = wire.RegisterInterface(
struct{ BlockchainMessage }{},
wire.ConcreteType{&bcBlockRequestMessage{}, msgTypeBlockRequest},
wire.ConcreteType{&bcBlockResponseMessage{}, msgTypeBlockResponse},
wire.ConcreteType{&bcStatusResponseMessage{}, msgTypeStatusResponse},
wire.ConcreteType{&bcStatusRequestMessage{}, msgTypeStatusRequest},
)
func RegisterBlockchainMessages(cdc *amino.Codec) {
cdc.RegisterInterface((*BlockchainMessage)(nil), nil)
cdc.RegisterConcrete(&bcBlockRequestMessage{}, "tendermint/mempool/BlockRequest", nil)
cdc.RegisterConcrete(&bcBlockResponseMessage{}, "tendermint/mempool/BlockResponse", nil)
cdc.RegisterConcrete(&bcNoBlockResponseMessage{}, "tendermint/mempool/NoBlockResponse", nil)
cdc.RegisterConcrete(&bcStatusResponseMessage{}, "tendermint/mempool/StatusResponse", nil)
cdc.RegisterConcrete(&bcStatusRequestMessage{}, "tendermint/mempool/StatusRequest", nil)
}
// DecodeMessage decodes BlockchainMessage.
// TODO: ensure that bz is completely read.
func DecodeMessage(bz []byte) (msgType byte, msg BlockchainMessage, err error) {
msgType = bz[0]
n := int(0)
r := bytes.NewReader(bz)
msg = wire.ReadBinary(struct{ BlockchainMessage }{}, r, maxBlockchainResponseSize, &n, &err).(struct{ BlockchainMessage }).BlockchainMessage
if err != nil && n != len(bz) {
err = errors.New("DecodeMessage() had bytes left over")
func DecodeMessage(bz []byte) (msg BlockchainMessage, err error) {
if len(bz) > maxMsgSize {
return msg, fmt.Errorf("Msg exceeds max size (%d > %d)",
len(bz), maxMsgSize)
}
err = cdc.UnmarshalBinaryBare(bz, &msg)
if err != nil {
err = cmn.ErrorWrap(err, "DecodeMessage() had bytes left over")
}
return
}
@ -308,16 +359,23 @@ func DecodeMessage(bz []byte) (msgType byte, msg BlockchainMessage, err error) {
//-------------------------------------
type bcBlockRequestMessage struct {
Height int
Height int64
}
func (m *bcBlockRequestMessage) String() string {
return cmn.Fmt("[bcBlockRequestMessage %v]", m.Height)
}
type bcNoBlockResponseMessage struct {
Height int64
}
func (brm *bcNoBlockResponseMessage) String() string {
return cmn.Fmt("[bcNoBlockResponseMessage %d]", brm.Height)
}
//-------------------------------------
// NOTE: keep up-to-date with maxBlockchainResponseSize
type bcBlockResponseMessage struct {
Block *types.Block
}
@ -329,7 +387,7 @@ func (m *bcBlockResponseMessage) String() string {
//-------------------------------------
type bcStatusRequestMessage struct {
Height int
Height int64
}
func (m *bcStatusRequestMessage) String() string {
@ -339,7 +397,7 @@ func (m *bcStatusRequestMessage) String() string {
//-------------------------------------
type bcStatusResponseMessage struct {
Height int
Height int64
}
func (m *bcStatusResponseMessage) String() string {

206
blockchain/reactor_test.go Normal file
View File

@ -0,0 +1,206 @@
package blockchain
import (
"testing"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
func makeStateAndBlockStore(logger log.Logger) (sm.State, *BlockStore) {
config := cfg.ResetTestRoot("blockchain_reactor_test")
// blockDB := dbm.NewDebugDB("blockDB", dbm.NewMemDB())
// stateDB := dbm.NewDebugDB("stateDB", dbm.NewMemDB())
blockDB := dbm.NewMemDB()
stateDB := dbm.NewMemDB()
blockStore := NewBlockStore(blockDB)
state, err := sm.LoadStateFromDBOrGenesisFile(stateDB, config.GenesisFile())
if err != nil {
panic(cmn.ErrorWrap(err, "error constructing state from genesis file"))
}
return state, blockStore
}
func newBlockchainReactor(logger log.Logger, maxBlockHeight int64) *BlockchainReactor {
state, blockStore := makeStateAndBlockStore(logger)
// Make the blockchainReactor itself
fastSync := true
var nilApp proxy.AppConnConsensus
blockExec := sm.NewBlockExecutor(dbm.NewMemDB(), log.TestingLogger(), nilApp,
types.MockMempool{}, types.MockEvidencePool{})
bcReactor := NewBlockchainReactor(state.Copy(), blockExec, blockStore, fastSync)
bcReactor.SetLogger(logger.With("module", "blockchain"))
// Next: we need to set a switch in order for peers to be added in
bcReactor.Switch = p2p.NewSwitch(cfg.DefaultP2PConfig())
// Lastly: let's add some blocks in
for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ {
firstBlock := makeBlock(blockHeight, state)
secondBlock := makeBlock(blockHeight+1, state)
firstParts := firstBlock.MakePartSet(state.ConsensusParams.BlockGossip.BlockPartSizeBytes)
blockStore.SaveBlock(firstBlock, firstParts, secondBlock.LastCommit)
}
return bcReactor
}
func TestNoBlockResponse(t *testing.T) {
maxBlockHeight := int64(20)
bcr := newBlockchainReactor(log.TestingLogger(), maxBlockHeight)
bcr.Start()
defer bcr.Stop()
// Add some peers in
peer := newbcrTestPeer(p2p.ID(cmn.RandStr(12)))
bcr.AddPeer(peer)
chID := byte(0x01)
tests := []struct {
height int64
existent bool
}{
{maxBlockHeight + 2, false},
{10, true},
{1, true},
{100, false},
}
// receive a request message from peer,
// wait for our response to be received on the peer
for _, tt := range tests {
reqBlockMsg := &bcBlockRequestMessage{tt.height}
reqBlockBytes := cdc.MustMarshalBinaryBare(reqBlockMsg)
bcr.Receive(chID, peer, reqBlockBytes)
msg := peer.lastBlockchainMessage()
if tt.existent {
if blockMsg, ok := msg.(*bcBlockResponseMessage); !ok {
t.Fatalf("Expected to receive a block response for height %d", tt.height)
} else if blockMsg.Block.Height != tt.height {
t.Fatalf("Expected response to be for height %d, got %d", tt.height, blockMsg.Block.Height)
}
} else {
if noBlockMsg, ok := msg.(*bcNoBlockResponseMessage); !ok {
t.Fatalf("Expected to receive a no block response for height %d", tt.height)
} else if noBlockMsg.Height != tt.height {
t.Fatalf("Expected response to be for height %d, got %d", tt.height, noBlockMsg.Height)
}
}
}
}
/*
// 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 TestBadBlockStopsPeer(t *testing.T) {
maxBlockHeight := int64(20)
bcr := newBlockchainReactor(log.TestingLogger(), maxBlockHeight)
bcr.Start()
defer bcr.Stop()
// Add some peers in
peer := newbcrTestPeer(p2p.ID(cmn.RandStr(12)))
// XXX: This doesn't add the peer to anything,
// so it's hard to check that it's later removed
bcr.AddPeer(peer)
assert.True(t, bcr.Switch.Peers().Size() > 0)
// send a bad block from the peer
// default blocks already dont have commits, so should fail
block := bcr.store.LoadBlock(3)
msg := &bcBlockResponseMessage{Block: block}
peer.Send(BlockchainChannel, struct{ BlockchainMessage }{msg})
ticker := time.NewTicker(time.Millisecond * 10)
timer := time.NewTimer(time.Second * 2)
LOOP:
for {
select {
case <-ticker.C:
if bcr.Switch.Peers().Size() == 0 {
break LOOP
}
case <-timer.C:
t.Fatal("Timed out waiting to disconnect peer")
}
}
}
*/
//----------------------------------------------
// utility funcs
func makeTxs(height int64) (txs []types.Tx) {
for i := 0; i < 10; i++ {
txs = append(txs, types.Tx([]byte{byte(height), byte(i)}))
}
return txs
}
func makeBlock(height int64, state sm.State) *types.Block {
block, _ := state.MakeBlock(height, makeTxs(height), new(types.Commit))
return block
}
// The Test peer
type bcrTestPeer struct {
cmn.BaseService
id p2p.ID
ch chan interface{}
}
var _ p2p.Peer = (*bcrTestPeer)(nil)
func newbcrTestPeer(id p2p.ID) *bcrTestPeer {
bcr := &bcrTestPeer{
id: id,
ch: make(chan interface{}, 2),
}
bcr.BaseService = *cmn.NewBaseService(nil, "bcrTestPeer", bcr)
return bcr
}
func (tp *bcrTestPeer) lastBlockchainMessage() interface{} { return <-tp.ch }
func (tp *bcrTestPeer) TrySend(chID byte, msgBytes []byte) bool {
var msg BlockchainMessage
err := cdc.UnmarshalBinaryBare(msgBytes, &msg)
if err != nil {
panic(cmn.ErrorWrap(err, "Error while trying to parse a BlockchainMessage"))
}
if _, ok := msg.(*bcStatusResponseMessage); ok {
// Discard status response messages since they skew our results
// We only want to deal with:
// + bcBlockResponseMessage
// + bcNoBlockResponseMessage
} else {
tp.ch <- msg
}
return true
}
func (tp *bcrTestPeer) Send(chID byte, msgBytes []byte) bool { return tp.TrySend(chID, msgBytes) }
func (tp *bcrTestPeer) NodeInfo() p2p.NodeInfo { return p2p.NodeInfo{} }
func (tp *bcrTestPeer) Status() p2p.ConnectionStatus { return p2p.ConnectionStatus{} }
func (tp *bcrTestPeer) ID() p2p.ID { return tp.id }
func (tp *bcrTestPeer) IsOutbound() bool { return false }
func (tp *bcrTestPeer) IsPersistent() bool { return true }
func (tp *bcrTestPeer) Get(s string) interface{} { return s }
func (tp *bcrTestPeer) Set(string, interface{}) {}

View File

@ -1,20 +1,17 @@
package blockchain
import (
"bytes"
"encoding/json"
"fmt"
"io"
"sync"
. "github.com/tendermint/go-common"
dbm "github.com/tendermint/go-db"
"github.com/tendermint/go-wire"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tendermint/types"
)
/*
Simple low level store for blocks.
BlockStore is a simple low level store for blocks.
There are three types of information stored:
- BlockMeta: Meta information about each block
@ -23,17 +20,20 @@ There are three types of information stored:
Currently the precommit signatures are duplicated in the Block parts as
well as the Commit. In the future this may change, perhaps by moving
the Commit data outside the Block.
the Commit data outside the Block. (TODO)
Panics indicate probable corruption in the data
// NOTE: BlockStore methods will panic if they encounter errors
// deserializing loaded data, indicating probable corruption on disk.
*/
type BlockStore struct {
db dbm.DB
mtx sync.RWMutex
height int
height int64
}
// NewBlockStore returns a new BlockStore with the given DB,
// initialized to the last height that was committed to the DB.
func NewBlockStore(db dbm.DB) *BlockStore {
bsjson := LoadBlockStoreStateJSON(db)
return &BlockStore{
@ -42,134 +42,136 @@ func NewBlockStore(db dbm.DB) *BlockStore {
}
}
// Height() returns the last known contiguous block height.
func (bs *BlockStore) Height() int {
// Height returns the last known contiguous block height.
func (bs *BlockStore) Height() int64 {
bs.mtx.RLock()
defer bs.mtx.RUnlock()
return bs.height
}
func (bs *BlockStore) GetReader(key []byte) io.Reader {
bytez := bs.db.Get(key)
if bytez == nil {
// LoadBlock returns the block with the given height.
// If no block is found for that height, it returns nil.
func (bs *BlockStore) LoadBlock(height int64) *types.Block {
var blockMeta = bs.LoadBlockMeta(height)
if blockMeta == nil {
return nil
}
return bytes.NewReader(bytez)
}
func (bs *BlockStore) LoadBlock(height int) *types.Block {
var n int
var err error
r := bs.GetReader(calcBlockMetaKey(height))
if r == nil {
return nil
}
blockMeta := wire.ReadBinary(&types.BlockMeta{}, r, 0, &n, &err).(*types.BlockMeta)
if err != nil {
PanicCrisis(Fmt("Error reading block meta: %v", err))
}
bytez := []byte{}
var block = new(types.Block)
buf := []byte{}
for i := 0; i < blockMeta.BlockID.PartsHeader.Total; i++ {
part := bs.LoadBlockPart(height, i)
bytez = append(bytez, part.Bytes...)
buf = append(buf, part.Bytes...)
}
block := wire.ReadBinary(&types.Block{}, bytes.NewReader(bytez), 0, &n, &err).(*types.Block)
err := cdc.UnmarshalBinary(buf, block)
if err != nil {
PanicCrisis(Fmt("Error reading block: %v", err))
// NOTE: The existence of meta should imply the existence of the
// block. So, make sure meta is only saved after blocks are saved.
panic(cmn.ErrorWrap(err, "Error reading block"))
}
return block
}
func (bs *BlockStore) LoadBlockPart(height int, index int) *types.Part {
var n int
var err error
r := bs.GetReader(calcBlockPartKey(height, index))
if r == nil {
// LoadBlockPart returns the Part at the given index
// from the block at the given height.
// If no part is found for the given height and index, it returns nil.
func (bs *BlockStore) LoadBlockPart(height int64, index int) *types.Part {
var part = new(types.Part)
bz := bs.db.Get(calcBlockPartKey(height, index))
if len(bz) == 0 {
return nil
}
part := wire.ReadBinary(&types.Part{}, r, 0, &n, &err).(*types.Part)
err := cdc.UnmarshalBinaryBare(bz, part)
if err != nil {
PanicCrisis(Fmt("Error reading block part: %v", err))
panic(cmn.ErrorWrap(err, "Error reading block part"))
}
return part
}
func (bs *BlockStore) LoadBlockMeta(height int) *types.BlockMeta {
var n int
var err error
r := bs.GetReader(calcBlockMetaKey(height))
if r == nil {
// LoadBlockMeta returns the BlockMeta for the given height.
// If no block is found for the given height, it returns nil.
func (bs *BlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
var blockMeta = new(types.BlockMeta)
bz := bs.db.Get(calcBlockMetaKey(height))
if len(bz) == 0 {
return nil
}
blockMeta := wire.ReadBinary(&types.BlockMeta{}, r, 0, &n, &err).(*types.BlockMeta)
err := cdc.UnmarshalBinaryBare(bz, blockMeta)
if err != nil {
PanicCrisis(Fmt("Error reading block meta: %v", err))
panic(cmn.ErrorWrap(err, "Error reading block meta"))
}
return blockMeta
}
// The +2/3 and other Precommit-votes for block at `height`.
// This Commit comes from block.LastCommit for `height+1`.
func (bs *BlockStore) LoadBlockCommit(height int) *types.Commit {
var n int
var err error
r := bs.GetReader(calcBlockCommitKey(height))
if r == nil {
// LoadBlockCommit returns the Commit for the given height.
// This commit consists of the +2/3 and other Precommit-votes for block at `height`,
// and it comes from the block.LastCommit for `height+1`.
// If no commit is found for the given height, it returns nil.
func (bs *BlockStore) LoadBlockCommit(height int64) *types.Commit {
var commit = new(types.Commit)
bz := bs.db.Get(calcBlockCommitKey(height))
if len(bz) == 0 {
return nil
}
commit := wire.ReadBinary(&types.Commit{}, r, 0, &n, &err).(*types.Commit)
err := cdc.UnmarshalBinaryBare(bz, commit)
if err != nil {
PanicCrisis(Fmt("Error reading commit: %v", err))
panic(cmn.ErrorWrap(err, "Error reading block commit"))
}
return commit
}
// NOTE: the Precommit-vote heights are for the block at `height`
func (bs *BlockStore) LoadSeenCommit(height int) *types.Commit {
var n int
var err error
r := bs.GetReader(calcSeenCommitKey(height))
if r == nil {
// LoadSeenCommit returns the locally seen Commit for the given height.
// This is useful when we've seen a commit, but there has not yet been
// a new block at `height + 1` that includes this commit in its block.LastCommit.
func (bs *BlockStore) LoadSeenCommit(height int64) *types.Commit {
var commit = new(types.Commit)
bz := bs.db.Get(calcSeenCommitKey(height))
if len(bz) == 0 {
return nil
}
commit := wire.ReadBinary(&types.Commit{}, r, 0, &n, &err).(*types.Commit)
err := cdc.UnmarshalBinaryBare(bz, commit)
if err != nil {
PanicCrisis(Fmt("Error reading commit: %v", err))
panic(cmn.ErrorWrap(err, "Error reading block seen commit"))
}
return commit
}
// SaveBlock persists the given block, blockParts, and seenCommit to the underlying db.
// blockParts: Must be parts of the block
// seenCommit: The +2/3 precommits that were seen which committed at height.
// If all the nodes restart after committing a block,
// we need this to reload the precommits to catch-up nodes to the
// most recent height. Otherwise they'd stall at H-1.
func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
if block == nil {
cmn.PanicSanity("BlockStore can only save a non-nil block")
}
height := block.Height
if height != bs.Height()+1 {
PanicSanity(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.Height()+1, height))
if g, w := height, bs.Height()+1; g != w {
cmn.PanicSanity(cmn.Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", w, g))
}
if !blockParts.IsComplete() {
PanicSanity(Fmt("BlockStore can only save complete block part sets"))
cmn.PanicSanity(cmn.Fmt("BlockStore can only save complete block part sets"))
}
// Save block meta
blockMeta := types.NewBlockMeta(block, blockParts)
metaBytes := wire.BinaryBytes(blockMeta)
metaBytes := cdc.MustMarshalBinaryBare(blockMeta)
bs.db.Set(calcBlockMetaKey(height), metaBytes)
// Save block parts
for i := 0; i < blockParts.Total(); i++ {
bs.saveBlockPart(height, i, blockParts.GetPart(i))
part := blockParts.GetPart(i)
bs.saveBlockPart(height, i, part)
}
// Save block commit (duplicate and separate from the Block)
blockCommitBytes := wire.BinaryBytes(block.LastCommit)
blockCommitBytes := cdc.MustMarshalBinaryBare(block.LastCommit)
bs.db.Set(calcBlockCommitKey(height-1), blockCommitBytes)
// Save seen commit (seen +2/3 precommits for block)
// NOTE: we can delete this at a later height
seenCommitBytes := wire.BinaryBytes(seenCommit)
seenCommitBytes := cdc.MustMarshalBinaryBare(seenCommit)
bs.db.Set(calcSeenCommitKey(height), seenCommitBytes)
// Save new BlockStoreStateJSON descriptor
@ -184,29 +186,29 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
bs.db.SetSync(nil, nil)
}
func (bs *BlockStore) saveBlockPart(height int, index int, part *types.Part) {
func (bs *BlockStore) saveBlockPart(height int64, index int, part *types.Part) {
if height != bs.Height()+1 {
PanicSanity(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.Height()+1, height))
cmn.PanicSanity(cmn.Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.Height()+1, height))
}
partBytes := wire.BinaryBytes(part)
partBytes := cdc.MustMarshalBinaryBare(part)
bs.db.Set(calcBlockPartKey(height, index), partBytes)
}
//-----------------------------------------------------------------------------
func calcBlockMetaKey(height int) []byte {
func calcBlockMetaKey(height int64) []byte {
return []byte(fmt.Sprintf("H:%v", height))
}
func calcBlockPartKey(height int, partIndex int) []byte {
func calcBlockPartKey(height int64, partIndex int) []byte {
return []byte(fmt.Sprintf("P:%v:%v", height, partIndex))
}
func calcBlockCommitKey(height int) []byte {
func calcBlockCommitKey(height int64) []byte {
return []byte(fmt.Sprintf("C:%v", height))
}
func calcSeenCommitKey(height int) []byte {
func calcSeenCommitKey(height int64) []byte {
return []byte(fmt.Sprintf("SC:%v", height))
}
@ -215,28 +217,31 @@ func calcSeenCommitKey(height int) []byte {
var blockStoreKey = []byte("blockStore")
type BlockStoreStateJSON struct {
Height int
Height int64 `json:"height"`
}
// Save persists the blockStore state to the database as JSON.
func (bsj BlockStoreStateJSON) Save(db dbm.DB) {
bytes, err := json.Marshal(bsj)
bytes, err := cdc.MarshalJSON(bsj)
if err != nil {
PanicSanity(Fmt("Could not marshal state bytes: %v", err))
cmn.PanicSanity(cmn.Fmt("Could not marshal state bytes: %v", err))
}
db.SetSync(blockStoreKey, bytes)
}
// LoadBlockStoreStateJSON returns the BlockStoreStateJSON as loaded from disk.
// If no BlockStoreStateJSON was previously persisted, it returns the zero value.
func LoadBlockStoreStateJSON(db dbm.DB) BlockStoreStateJSON {
bytes := db.Get(blockStoreKey)
if bytes == nil {
if len(bytes) == 0 {
return BlockStoreStateJSON{
Height: 0,
}
}
bsj := BlockStoreStateJSON{}
err := json.Unmarshal(bytes, &bsj)
err := cdc.UnmarshalJSON(bytes, &bsj)
if err != nil {
PanicCrisis(Fmt("Could not unmarshal bytes: %X", bytes))
panic(fmt.Sprintf("Could not unmarshal bytes: %X", bytes))
}
return bsj
}

383
blockchain/store_test.go Normal file
View File

@ -0,0 +1,383 @@
package blockchain
import (
"bytes"
"fmt"
"runtime/debug"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
"github.com/tendermint/tendermint/types"
)
func TestLoadBlockStoreStateJSON(t *testing.T) {
db := db.NewMemDB()
bsj := &BlockStoreStateJSON{Height: 1000}
bsj.Save(db)
retrBSJ := LoadBlockStoreStateJSON(db)
assert.Equal(t, *bsj, retrBSJ, "expected the retrieved DBs to match")
}
func TestNewBlockStore(t *testing.T) {
db := db.NewMemDB()
db.Set(blockStoreKey, []byte(`{"height": 10000}`))
bs := NewBlockStore(db)
require.Equal(t, int64(10000), bs.Height(), "failed to properly parse blockstore")
panicCausers := []struct {
data []byte
wantErr string
}{
{[]byte("artful-doger"), "not unmarshal bytes"},
{[]byte(" "), "unmarshal bytes"},
}
for i, tt := range panicCausers {
// Expecting a panic here on trying to parse an invalid blockStore
_, _, panicErr := doFn(func() (interface{}, error) {
db.Set(blockStoreKey, tt.data)
_ = NewBlockStore(db)
return nil, nil
})
require.NotNil(t, panicErr, "#%d panicCauser: %q expected a panic", i, tt.data)
assert.Contains(t, panicErr.Error(), tt.wantErr, "#%d data: %q", i, tt.data)
}
db.Set(blockStoreKey, nil)
bs = NewBlockStore(db)
assert.Equal(t, bs.Height(), int64(0), "expecting nil bytes to be unmarshaled alright")
}
func freshBlockStore() (*BlockStore, db.DB) {
db := db.NewMemDB()
return NewBlockStore(db), db
}
var (
state, _ = makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
block = makeBlock(1, state)
partSet = block.MakePartSet(2)
part1 = partSet.GetPart(0)
part2 = partSet.GetPart(1)
seenCommit1 = &types.Commit{Precommits: []*types.Vote{{Height: 10,
Timestamp: time.Now().UTC()}}}
)
// TODO: This test should be simplified ...
func TestBlockStoreSaveLoadBlock(t *testing.T) {
state, bs := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
// check there are no blocks at various heights
noBlockHeights := []int64{0, -1, 100, 1000, 2}
for i, height := range noBlockHeights {
if g := bs.LoadBlock(height); g != nil {
t.Errorf("#%d: height(%d) got a block; want nil", i, height)
}
}
// save a block
block := makeBlock(bs.Height()+1, state)
validPartSet := block.MakePartSet(2)
seenCommit := &types.Commit{Precommits: []*types.Vote{{Height: 10,
Timestamp: time.Now().UTC()}}}
bs.SaveBlock(block, partSet, seenCommit)
require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed")
incompletePartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 2})
uncontiguousPartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 0})
uncontiguousPartSet.AddPart(part2, false)
header1 := types.Header{
Height: 1,
NumTxs: 100,
ChainID: "block_test",
Time: time.Now(),
}
header2 := header1
header2.Height = 4
// End of setup, test data
commitAtH10 := &types.Commit{Precommits: []*types.Vote{{Height: 10,
Timestamp: time.Now().UTC()}}}
tuples := []struct {
block *types.Block
parts *types.PartSet
seenCommit *types.Commit
wantErr bool
wantPanic string
corruptBlockInDB bool
corruptCommitInDB bool
corruptSeenCommitInDB bool
eraseCommitInDB bool
eraseSeenCommitInDB bool
}{
{
block: newBlock(&header1, commitAtH10),
parts: validPartSet,
seenCommit: seenCommit1,
},
{
block: nil,
wantPanic: "only save a non-nil block",
},
{
block: newBlock(&header2, commitAtH10),
parts: uncontiguousPartSet,
wantPanic: "only save contiguous blocks", // and incomplete and uncontiguous parts
},
{
block: newBlock(&header1, commitAtH10),
parts: incompletePartSet,
wantPanic: "only save complete block", // incomplete parts
},
{
block: newBlock(&header1, commitAtH10),
parts: validPartSet,
seenCommit: seenCommit1,
corruptCommitInDB: true, // Corrupt the DB's commit entry
wantPanic: "Error reading block commit",
},
{
block: newBlock(&header1, commitAtH10),
parts: validPartSet,
seenCommit: seenCommit1,
wantPanic: "Error reading block",
corruptBlockInDB: true, // Corrupt the DB's block entry
},
{
block: newBlock(&header1, commitAtH10),
parts: validPartSet,
seenCommit: seenCommit1,
// Expecting no error and we want a nil back
eraseSeenCommitInDB: true,
},
{
block: newBlock(&header1, commitAtH10),
parts: validPartSet,
seenCommit: seenCommit1,
corruptSeenCommitInDB: true,
wantPanic: "Error reading block seen commit",
},
{
block: newBlock(&header1, commitAtH10),
parts: validPartSet,
seenCommit: seenCommit1,
// Expecting no error and we want a nil back
eraseCommitInDB: true,
},
}
type quad struct {
block *types.Block
commit *types.Commit
meta *types.BlockMeta
seenCommit *types.Commit
}
for i, tuple := range tuples {
bs, db := freshBlockStore()
// SaveBlock
res, err, panicErr := doFn(func() (interface{}, error) {
bs.SaveBlock(tuple.block, tuple.parts, tuple.seenCommit)
if tuple.block == nil {
return nil, nil
}
if tuple.corruptBlockInDB {
db.Set(calcBlockMetaKey(tuple.block.Height), []byte("block-bogus"))
}
bBlock := bs.LoadBlock(tuple.block.Height)
bBlockMeta := bs.LoadBlockMeta(tuple.block.Height)
if tuple.eraseSeenCommitInDB {
db.Delete(calcSeenCommitKey(tuple.block.Height))
}
if tuple.corruptSeenCommitInDB {
db.Set(calcSeenCommitKey(tuple.block.Height), []byte("bogus-seen-commit"))
}
bSeenCommit := bs.LoadSeenCommit(tuple.block.Height)
commitHeight := tuple.block.Height - 1
if tuple.eraseCommitInDB {
db.Delete(calcBlockCommitKey(commitHeight))
}
if tuple.corruptCommitInDB {
db.Set(calcBlockCommitKey(commitHeight), []byte("foo-bogus"))
}
bCommit := bs.LoadBlockCommit(commitHeight)
return &quad{block: bBlock, seenCommit: bSeenCommit, commit: bCommit,
meta: bBlockMeta}, nil
})
if subStr := tuple.wantPanic; subStr != "" {
if panicErr == nil {
t.Errorf("#%d: want a non-nil panic", i)
} else if got := panicErr.Error(); !strings.Contains(got, subStr) {
t.Errorf("#%d:\n\tgotErr: %q\nwant substring: %q", i, got, subStr)
}
continue
}
if tuple.wantErr {
if err == nil {
t.Errorf("#%d: got nil error", i)
}
continue
}
assert.Nil(t, panicErr, "#%d: unexpected panic", i)
assert.Nil(t, err, "#%d: expecting a non-nil error", i)
qua, ok := res.(*quad)
if !ok || qua == nil {
t.Errorf("#%d: got nil quad back; gotType=%T", i, res)
continue
}
if tuple.eraseSeenCommitInDB {
assert.Nil(t, qua.seenCommit,
"erased the seenCommit in the DB hence we should get back a nil seenCommit")
}
if tuple.eraseCommitInDB {
assert.Nil(t, qua.commit,
"erased the commit in the DB hence we should get back a nil commit")
}
}
}
func TestLoadBlockPart(t *testing.T) {
bs, db := freshBlockStore()
height, index := int64(10), 1
loadPart := func() (interface{}, error) {
part := bs.LoadBlockPart(height, index)
return part, nil
}
// Initially no contents.
// 1. Requesting for a non-existent block shouldn't fail
res, _, panicErr := doFn(loadPart)
require.Nil(t, panicErr, "a non-existent block part shouldn't cause a panic")
require.Nil(t, res, "a non-existent block part should return nil")
// 2. Next save a corrupted block then try to load it
db.Set(calcBlockPartKey(height, index), []byte("Tendermint"))
res, _, panicErr = doFn(loadPart)
require.NotNil(t, panicErr, "expecting a non-nil panic")
require.Contains(t, panicErr.Error(), "Error reading block part")
// 3. A good block serialized and saved to the DB should be retrievable
db.Set(calcBlockPartKey(height, index), cdc.MustMarshalBinaryBare(part1))
gotPart, _, panicErr := doFn(loadPart)
require.Nil(t, panicErr, "an existent and proper block should not panic")
require.Nil(t, res, "a properly saved block should return a proper block")
require.Equal(t, gotPart.(*types.Part).Hash(), part1.Hash(),
"expecting successful retrieval of previously saved block")
}
func TestLoadBlockMeta(t *testing.T) {
bs, db := freshBlockStore()
height := int64(10)
loadMeta := func() (interface{}, error) {
meta := bs.LoadBlockMeta(height)
return meta, nil
}
// Initially no contents.
// 1. Requesting for a non-existent blockMeta shouldn't fail
res, _, panicErr := doFn(loadMeta)
require.Nil(t, panicErr, "a non-existent blockMeta shouldn't cause a panic")
require.Nil(t, res, "a non-existent blockMeta should return nil")
// 2. Next save a corrupted blockMeta then try to load it
db.Set(calcBlockMetaKey(height), []byte("Tendermint-Meta"))
res, _, panicErr = doFn(loadMeta)
require.NotNil(t, panicErr, "expecting a non-nil panic")
require.Contains(t, panicErr.Error(), "Error reading block meta")
// 3. A good blockMeta serialized and saved to the DB should be retrievable
meta := &types.BlockMeta{}
db.Set(calcBlockMetaKey(height), cdc.MustMarshalBinaryBare(meta))
gotMeta, _, panicErr := doFn(loadMeta)
require.Nil(t, panicErr, "an existent and proper block should not panic")
require.Nil(t, res, "a properly saved blockMeta should return a proper blocMeta ")
require.Equal(t, cdc.MustMarshalBinaryBare(meta), cdc.MustMarshalBinaryBare(gotMeta),
"expecting successful retrieval of previously saved blockMeta")
}
func TestBlockFetchAtHeight(t *testing.T) {
state, bs := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
block := makeBlock(bs.Height()+1, state)
partSet := block.MakePartSet(2)
seenCommit := &types.Commit{Precommits: []*types.Vote{{Height: 10,
Timestamp: time.Now().UTC()}}}
bs.SaveBlock(block, partSet, seenCommit)
require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed")
blockAtHeight := bs.LoadBlock(bs.Height())
bz1 := cdc.MustMarshalBinaryBare(block)
bz2 := cdc.MustMarshalBinaryBare(blockAtHeight)
require.Equal(t, bz1, bz2)
require.Equal(t, block.Hash(), blockAtHeight.Hash(),
"expecting a successful load of the last saved block")
blockAtHeightPlus1 := bs.LoadBlock(bs.Height() + 1)
require.Nil(t, blockAtHeightPlus1, "expecting an unsuccessful load of Height()+1")
blockAtHeightPlus2 := bs.LoadBlock(bs.Height() + 2)
require.Nil(t, blockAtHeightPlus2, "expecting an unsuccessful load of Height()+2")
}
func doFn(fn func() (interface{}, error)) (res interface{}, err error, panicErr error) {
defer func() {
if r := recover(); r != nil {
switch e := r.(type) {
case error:
panicErr = e
case string:
panicErr = fmt.Errorf("%s", e)
default:
if st, ok := r.(fmt.Stringer); ok {
panicErr = fmt.Errorf("%s", st)
} else {
panicErr = fmt.Errorf("%s", debug.Stack())
}
}
}
}()
res, err = fn()
return res, err, panicErr
}
func newBlock(hdr *types.Header, lastCommit *types.Commit) *types.Block {
return &types.Block{
Header: hdr,
LastCommit: lastCommit,
}
}

13
blockchain/wire.go Normal file
View File

@ -0,0 +1,13 @@
package blockchain
import (
amino "github.com/tendermint/go-amino"
"github.com/tendermint/go-crypto"
)
var cdc = amino.NewCodec()
func init() {
RegisterBlockchainMessages(cdc)
crypto.RegisterAmino(cdc)
}

View File

@ -1,33 +0,0 @@
---
machine:
environment:
MACH_PREFIX: tendermint-test-mach
DOCKER_VERSION: 1.10.0
DOCKER_MACHINE_VERSION: 0.9.0
GOPATH: "$HOME/.go_project"
PROJECT_PARENT_PATH: "$GOPATH/src/github.com/$CIRCLE_PROJECT_USERNAME"
PROJECT_PATH: "$PROJECT_PARENT_PATH/$CIRCLE_PROJECT_REPONAME"
hosts:
localhost: 127.0.0.1
dependencies:
override:
- curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | sudo bash -s -- $DOCKER_VERSION
- sudo start docker
- sudo curl -sSL -o /usr/bin/docker-machine "https://github.com/docker/machine/releases/download/v$DOCKER_MACHINE_VERSION/docker-machine-`uname -s`-`uname -m`"; sudo chmod 0755 /usr/bin/docker-machine
- mkdir -p "$PROJECT_PARENT_PATH"
- ln -sf "$HOME/$CIRCLE_PROJECT_REPONAME/" "$PROJECT_PATH"
post:
- go version
- docker version
- docker-machine version
test:
override:
- cd "$PROJECT_PATH" && set -o pipefail && make test_integrations 2>&1 | tee test_integrations.log:
timeout: 1800
post:
- cd "$PROJECT_PATH" && mv test_integrations.log "${CIRCLE_ARTIFACTS}"
- cd "$PROJECT_PATH" && bash <(curl -s https://codecov.io/bash) -f coverage.txt
- cd "$PROJECT_PATH" && mv coverage.txt "${CIRCLE_ARTIFACTS}"
- cd "$PROJECT_PATH" && cp test/logs/messages "${CIRCLE_ARTIFACTS}/docker_logs.txt"

View File

@ -0,0 +1,53 @@
package main
import (
"flag"
"os"
crypto "github.com/tendermint/go-crypto"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
priv_val "github.com/tendermint/tendermint/types/priv_validator"
)
func main() {
var (
addr = flag.String("addr", ":46659", "Address of client to connect to")
chainID = flag.String("chain-id", "mychain", "chain id")
privValPath = flag.String("priv", "", "priv val file path")
logger = log.NewTMLogger(
log.NewSyncWriter(os.Stdout),
).With("module", "priv_val")
)
flag.Parse()
logger.Info(
"Starting private validator",
"addr", *addr,
"chainID", *chainID,
"privPath", *privValPath,
)
privVal := priv_val.LoadFilePV(*privValPath)
rs := priv_val.NewRemoteSigner(
logger,
*chainID,
*addr,
privVal,
crypto.GenPrivKeyEd25519(),
)
err := rs.Start()
if err != nil {
panic(err)
}
cmn.TrapSignal(func() {
err := rs.Stop()
if err != nil {
panic(err)
}
})
}

View File

@ -0,0 +1,32 @@
package commands
import (
"fmt"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/p2p"
cmn "github.com/tendermint/tmlibs/common"
)
// GenNodeKeyCmd allows the generation of a node key. It prints node's ID to
// the standard output.
var GenNodeKeyCmd = &cobra.Command{
Use: "gen_node_key",
Short: "Generate a node key for this node and print its ID",
RunE: genNodeKey,
}
func genNodeKey(cmd *cobra.Command, args []string) error {
nodeKeyFile := config.NodeKeyFile()
if cmn.FileExists(nodeKeyFile) {
return fmt.Errorf("node key at %s already exists", nodeKeyFile)
}
nodeKey, err := p2p.LoadOrGenNodeKey(nodeKeyFile)
if err != nil {
return err
}
fmt.Println(nodeKey.ID())
return nil
}

View File

@ -5,23 +5,23 @@ import (
"github.com/spf13/cobra"
"github.com/tendermint/go-wire"
"github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
)
var genValidatorCmd = &cobra.Command{
// GenValidatorCmd allows the generation of a keypair for a
// validator.
var GenValidatorCmd = &cobra.Command{
Use: "gen_validator",
Short: "Generate new validator keypair",
Run: genValidator,
}
func init() {
RootCmd.AddCommand(genValidatorCmd)
}
func genValidator(cmd *cobra.Command, args []string) {
privValidator := types.GenPrivValidator()
privValidatorJSONBytes := wire.JSONBytesPretty(privValidator)
pv := pvm.GenFilePV("")
jsbz, err := cdc.MarshalJSON(pv)
if err != nil {
panic(err)
}
fmt.Printf(`%v
`, string(privValidatorJSONBytes))
`, string(jsbz))
}

View File

@ -1,47 +1,67 @@
package commands
import (
"os"
"github.com/spf13/cobra"
cmn "github.com/tendermint/go-common"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
cmn "github.com/tendermint/tmlibs/common"
)
var initFilesCmd = &cobra.Command{
// InitFilesCmd initialises a fresh Tendermint Core instance.
var InitFilesCmd = &cobra.Command{
Use: "init",
Short: "Initialize Tendermint",
Run: initFiles,
RunE: initFiles,
}
func init() {
RootCmd.AddCommand(initFilesCmd)
func initFiles(cmd *cobra.Command, args []string) error {
return initFilesWithConfig(config)
}
func initFiles(cmd *cobra.Command, args []string) {
privValFile := config.GetString("priv_validator_file")
if _, err := os.Stat(privValFile); os.IsNotExist(err) {
privValidator := types.GenPrivValidator()
privValidator.SetFile(privValFile)
privValidator.Save()
genFile := config.GetString("genesis_file")
if _, err := os.Stat(genFile); os.IsNotExist(err) {
genDoc := types.GenesisDoc{
ChainID: cmn.Fmt("test-chain-%v", cmn.RandStr(6)),
}
genDoc.Validators = []types.GenesisValidator{types.GenesisValidator{
PubKey: privValidator.PubKey,
Amount: 10,
}}
genDoc.SaveAs(genFile)
}
log.Notice("Initialized tendermint", "genesis", config.GetString("genesis_file"), "priv_validator", config.GetString("priv_validator_file"))
func initFilesWithConfig(config *cfg.Config) error {
// private validator
privValFile := config.PrivValidatorFile()
var pv *pvm.FilePV
if cmn.FileExists(privValFile) {
pv = pvm.LoadFilePV(privValFile)
logger.Info("Found private validator", "path", privValFile)
} else {
log.Notice("Already initialized", "priv_validator", config.GetString("priv_validator_file"))
pv = pvm.GenFilePV(privValFile)
pv.Save()
logger.Info("Generated private validator", "path", privValFile)
}
nodeKeyFile := config.NodeKeyFile()
if cmn.FileExists(nodeKeyFile) {
logger.Info("Found node key", "path", nodeKeyFile)
} else {
if _, err := p2p.LoadOrGenNodeKey(nodeKeyFile); err != nil {
return err
}
logger.Info("Generated node key", "path", nodeKeyFile)
}
// genesis file
genFile := config.GenesisFile()
if cmn.FileExists(genFile) {
logger.Info("Found genesis file", "path", genFile)
} else {
genDoc := types.GenesisDoc{
ChainID: cmn.Fmt("test-chain-%v", cmn.RandStr(6)),
}
genDoc.Validators = []types.GenesisValidator{{
PubKey: pv.GetPubKey(),
Power: 10,
}}
if err := genDoc.SaveAs(genFile); err != nil {
return err
}
logger.Info("Generated genesis file", "path", genFile)
}
return nil
}

View File

@ -0,0 +1,87 @@
package commands
import (
"fmt"
"net/url"
"github.com/spf13/cobra"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tendermint/lite/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"
)
// LiteCmd represents the base command when called without any subcommands
var LiteCmd = &cobra.Command{
Use: "lite",
Short: "Run lite-client proxy server, verifying tendermint rpc",
Long: `This node will run a secure proxy to a tendermint rpc server.
All calls that can be tracked back to a block header by a proof
will be verified before passing them back to the caller. Other that
that it will present the same interface as a full tendermint node,
just with added trust and running locally.`,
RunE: runProxy,
SilenceUsage: true,
}
var (
listenAddr string
nodeAddr string
chainID string
home string
)
func init() {
LiteCmd.Flags().StringVar(&listenAddr, "laddr", "tcp://localhost:8888", "Serve the proxy on the given address")
LiteCmd.Flags().StringVar(&nodeAddr, "node", "tcp://localhost:46657", "Connect to a Tendermint node at this address")
LiteCmd.Flags().StringVar(&chainID, "chain-id", "tendermint", "Specify the Tendermint chain ID")
LiteCmd.Flags().StringVar(&home, "home-dir", ".tendermint-lite", "Specify the home directory")
}
func ensureAddrHasSchemeOrDefaultToTCP(addr string) (string, error) {
u, err := url.Parse(addr)
if err != nil {
return "", err
}
switch u.Scheme {
case "tcp", "unix":
case "":
u.Scheme = "tcp"
default:
return "", fmt.Errorf("unknown scheme %q, use either tcp or unix", u.Scheme)
}
return u.String(), nil
}
func runProxy(cmd *cobra.Command, args []string) error {
nodeAddr, err := ensureAddrHasSchemeOrDefaultToTCP(nodeAddr)
if err != nil {
return err
}
listenAddr, err := ensureAddrHasSchemeOrDefaultToTCP(listenAddr)
if err != nil {
return err
}
// First, connect a client
node := rpcclient.NewHTTP(nodeAddr, "/websocket")
cert, err := proxy.GetCertifier(chainID, home, nodeAddr)
if err != nil {
return err
}
sc := proxy.SecureClient(node, cert)
err = proxy.StartProxy(sc, listenAddr, logger)
if err != nil {
return err
}
cmn.TrapSignal(func() {
// TODO: close up shop
})
return nil
}

View File

@ -1,36 +1,31 @@
package commands
import (
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"github.com/tendermint/go-p2p/upnp"
"github.com/tendermint/tendermint/p2p/upnp"
)
var probeUpnpCmd = &cobra.Command{
// ProbeUpnpCmd adds capabilities to test the UPnP functionality.
var ProbeUpnpCmd = &cobra.Command{
Use: "probe_upnp",
Short: "Test UPnP functionality",
Run: probeUpnp,
RunE: probeUpnp,
}
func init() {
RootCmd.AddCommand(probeUpnpCmd)
}
func probeUpnp(cmd *cobra.Command, args []string) {
capabilities, err := upnp.Probe()
func probeUpnp(cmd *cobra.Command, args []string) error {
capabilities, err := upnp.Probe(logger)
if err != nil {
fmt.Println("Probe failed: %v", err)
fmt.Println("Probe failed: ", err)
} else {
fmt.Println("Probe success!")
jsonBytes, err := json.Marshal(capabilities)
jsonBytes, err := cdc.MarshalJSON(capabilities)
if err != nil {
panic(err)
return err
}
fmt.Println(string(jsonBytes))
}
return nil
}

View File

@ -1,40 +1,26 @@
package commands
import (
"fmt"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/consensus"
"github.com/spf13/cobra"
)
var replayCmd = &cobra.Command{
Use: "replay [walfile]",
// ReplayCmd allows replaying of messages from the WAL.
var ReplayCmd = &cobra.Command{
Use: "replay",
Short: "Replay messages from WAL",
Run: func(cmd *cobra.Command, args []string) {
if len(args) > 1 {
consensus.RunReplayFile(config, args[1], false)
} else {
fmt.Println("replay requires an argument (walfile)")
}
consensus.RunReplayFile(config.BaseConfig, config.Consensus, false)
},
}
var replayConsoleCmd = &cobra.Command{
Use: "replay_console [walfile]",
// ReplayConsoleCmd allows replaying of messages from the WAL in a
// console.
var ReplayConsoleCmd = &cobra.Command{
Use: "replay_console",
Short: "Replay messages from WAL in a console",
Run: func(cmd *cobra.Command, args []string) {
if len(args) > 1 {
consensus.RunReplayFile(config, args[1], true)
} else {
fmt.Println("replay_console requires an argument (walfile)")
}
consensus.RunReplayFile(config.BaseConfig, config.Consensus, true)
},
}
func init() {
RootCmd.AddCommand(replayCmd)
RootCmd.AddCommand(replayConsoleCmd)
}

View File

@ -5,58 +5,57 @@ import (
"github.com/spf13/cobra"
cfg "github.com/tendermint/go-config"
"github.com/tendermint/log15"
"github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
"github.com/tendermint/tmlibs/log"
)
var resetAllCmd = &cobra.Command{
// ResetAllCmd removes the database of this Tendermint core
// instance.
var ResetAllCmd = &cobra.Command{
Use: "unsafe_reset_all",
Short: "(unsafe) Remove all the data and WAL, reset this node's validator",
Run: resetAll,
}
var resetPrivValidatorCmd = &cobra.Command{
// ResetPrivValidatorCmd resets the private validator files.
var ResetPrivValidatorCmd = &cobra.Command{
Use: "unsafe_reset_priv_validator",
Short: "(unsafe) Reset this node's validator",
Run: resetPrivValidator,
}
func init() {
RootCmd.AddCommand(resetAllCmd)
RootCmd.AddCommand(resetPrivValidatorCmd)
// ResetAll removes the privValidator files.
// Exported so other CLI tools can use it.
func ResetAll(dbDir, privValFile string, logger log.Logger) {
resetFilePV(privValFile, logger)
if err := os.RemoveAll(dbDir); err != nil {
logger.Error("Error removing directory", "err", err)
return
}
logger.Info("Removed all data", "dir", dbDir)
}
// XXX: this is totally unsafe.
// it's only suitable for testnets.
func resetAll(cmd *cobra.Command, args []string) {
ResetAll(config, log)
ResetAll(config.DBDir(), config.PrivValidatorFile(), logger)
}
// XXX: this is totally unsafe.
// it's only suitable for testnets.
func resetPrivValidator(cmd *cobra.Command, args []string) {
ResetPrivValidator(config, log)
resetFilePV(config.PrivValidatorFile(), logger)
}
// Exported so other CLI tools can use it
func ResetAll(c cfg.Config, l log15.Logger) {
ResetPrivValidator(c, l)
os.RemoveAll(c.GetString("db_dir"))
}
func ResetPrivValidator(c cfg.Config, l log15.Logger) {
func resetFilePV(privValFile string, logger log.Logger) {
// Get PrivValidator
var privValidator *types.PrivValidator
privValidatorFile := c.GetString("priv_validator_file")
if _, err := os.Stat(privValidatorFile); err == nil {
privValidator = types.LoadPrivValidator(privValidatorFile)
privValidator.Reset()
l.Notice("Reset PrivValidator", "file", privValidatorFile)
if _, err := os.Stat(privValFile); err == nil {
pv := pvm.LoadFilePV(privValFile)
pv.Reset()
logger.Info("Reset PrivValidator", "file", privValFile)
} else {
privValidator = types.GenPrivValidator()
privValidator.SetFile(privValidatorFile)
privValidator.Save()
l.Notice("Generated PrivValidator", "file", privValidatorFile)
pv := pvm.GenFilePV(privValFile)
pv.Save()
logger.Info("Generated PrivValidator", "file", privValFile)
}
}

View File

@ -1,31 +1,63 @@
package commands
import (
"github.com/spf13/cobra"
"os"
"github.com/tendermint/go-logger"
tmcfg "github.com/tendermint/tendermint/config/tendermint"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tmlibs/cli"
tmflags "github.com/tendermint/tmlibs/cli/flags"
"github.com/tendermint/tmlibs/log"
)
var (
config = tmcfg.GetConfig("")
log = logger.New("module", "main")
config = cfg.DefaultConfig()
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
)
//global flag
var logLevel string
func init() {
registerFlagsRootCmd(RootCmd)
}
func registerFlagsRootCmd(cmd *cobra.Command) {
cmd.PersistentFlags().String("log_level", config.LogLevel, "Log level")
}
// ParseConfig retrieves the default environment configuration,
// sets up the Tendermint root and ensures that the root exists
func ParseConfig() (*cfg.Config, error) {
conf := cfg.DefaultConfig()
err := viper.Unmarshal(conf)
if err != nil {
return nil, err
}
conf.SetRoot(conf.RootDir)
cfg.EnsureRoot(conf.RootDir)
return conf, err
}
// RootCmd is the root command for Tendermint core.
var RootCmd = &cobra.Command{
Use: "tendermint",
Short: "Tendermint Core (BFT Consensus) in Go",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// set the log level in the config and logger
config.Set("log_level", logLevel)
logger.SetLogLevel(logLevel)
PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
if cmd.Name() == VersionCmd.Name() {
return nil
}
config, err = ParseConfig()
if err != nil {
return err
}
logger, err = tmflags.ParseLogLevel(config.LogLevel, logger, cfg.DefaultLogLevel())
if err != nil {
return err
}
if viper.GetBool(cli.TraceFlag) {
logger = log.NewTracingLogger(logger)
}
logger = logger.With("module", "main")
return nil
},
}
func init() {
//parse flag and set config
RootCmd.PersistentFlags().StringVar(&logLevel, "log_level", config.GetString("log_level"), "Log level")
}

View File

@ -0,0 +1,176 @@
package commands
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"testing"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tmlibs/cli"
cmn "github.com/tendermint/tmlibs/common"
)
var (
defaultRoot = os.ExpandEnv("$HOME/.some/test/dir")
)
const (
rootName = "root"
)
// clearConfig clears env vars, the given root dir, and resets viper.
func clearConfig(dir string) {
if err := os.Unsetenv("TMHOME"); err != nil {
panic(err)
}
if err := os.Unsetenv("TM_HOME"); err != nil {
panic(err)
}
if err := os.RemoveAll(dir); err != nil {
panic(err)
}
viper.Reset()
config = cfg.DefaultConfig()
}
// prepare new rootCmd
func testRootCmd() *cobra.Command {
rootCmd := &cobra.Command{
Use: RootCmd.Use,
PersistentPreRunE: RootCmd.PersistentPreRunE,
Run: func(cmd *cobra.Command, args []string) {},
}
registerFlagsRootCmd(rootCmd)
var l string
rootCmd.PersistentFlags().String("log", l, "Log")
return rootCmd
}
func testSetup(rootDir string, args []string, env map[string]string) error {
clearConfig(defaultRoot)
rootCmd := testRootCmd()
cmd := cli.PrepareBaseCmd(rootCmd, "TM", defaultRoot)
// run with the args and env
args = append([]string{rootCmd.Use}, args...)
return cli.RunWithArgs(cmd, args, env)
}
func TestRootHome(t *testing.T) {
newRoot := filepath.Join(defaultRoot, "something-else")
cases := []struct {
args []string
env map[string]string
root string
}{
{nil, nil, defaultRoot},
{[]string{"--home", newRoot}, nil, newRoot},
{nil, map[string]string{"TMHOME": newRoot}, newRoot},
}
for i, tc := range cases {
idxString := strconv.Itoa(i)
err := testSetup(defaultRoot, tc.args, tc.env)
require.Nil(t, err, idxString)
assert.Equal(t, tc.root, config.RootDir, idxString)
assert.Equal(t, tc.root, config.P2P.RootDir, idxString)
assert.Equal(t, tc.root, config.Consensus.RootDir, idxString)
assert.Equal(t, tc.root, config.Mempool.RootDir, idxString)
}
}
func TestRootFlagsEnv(t *testing.T) {
// defaults
defaults := cfg.DefaultConfig()
defaultLogLvl := defaults.LogLevel
cases := []struct {
args []string
env map[string]string
logLevel string
}{
{[]string{"--log", "debug"}, nil, defaultLogLvl}, // wrong flag
{[]string{"--log_level", "debug"}, nil, "debug"}, // right flag
{nil, map[string]string{"TM_LOW": "debug"}, defaultLogLvl}, // wrong env flag
{nil, map[string]string{"MT_LOG_LEVEL": "debug"}, defaultLogLvl}, // wrong env prefix
{nil, map[string]string{"TM_LOG_LEVEL": "debug"}, "debug"}, // right env
}
for i, tc := range cases {
idxString := strconv.Itoa(i)
err := testSetup(defaultRoot, tc.args, tc.env)
require.Nil(t, err, idxString)
assert.Equal(t, tc.logLevel, config.LogLevel, idxString)
}
}
func TestRootConfig(t *testing.T) {
// write non-default config
nonDefaultLogLvl := "abc:debug"
cvals := map[string]string{
"log_level": nonDefaultLogLvl,
}
cases := []struct {
args []string
env map[string]string
logLvl string
}{
{nil, nil, nonDefaultLogLvl}, // should load config
{[]string{"--log_level=abc:info"}, nil, "abc:info"}, // flag over rides
{nil, map[string]string{"TM_LOG_LEVEL": "abc:info"}, "abc:info"}, // env over rides
}
for i, tc := range cases {
idxString := strconv.Itoa(i)
clearConfig(defaultRoot)
// XXX: path must match cfg.defaultConfigPath
configFilePath := filepath.Join(defaultRoot, "config")
err := cmn.EnsureDir(configFilePath, 0700)
require.Nil(t, err)
// write the non-defaults to a different path
// TODO: support writing sub configs so we can test that too
err = WriteConfigVals(configFilePath, cvals)
require.Nil(t, err)
rootCmd := testRootCmd()
cmd := cli.PrepareBaseCmd(rootCmd, "TM", defaultRoot)
// run with the args and env
tc.args = append([]string{rootCmd.Use}, tc.args...)
err = cli.RunWithArgs(cmd, tc.args, tc.env)
require.Nil(t, err, idxString)
assert.Equal(t, tc.logLvl, config.LogLevel, idxString)
}
}
// WriteConfigVals writes a toml file with the given values.
// It returns an error if writing was impossible.
func WriteConfigVals(dir string, vals map[string]string) error {
data := ""
for k, v := range vals {
data = data + fmt.Sprintf("%s = \"%s\"\n", k, v)
}
cfile := filepath.Join(dir, "config.toml")
return ioutil.WriteFile(cfile, []byte(data), 0666)
}

View File

@ -1,124 +1,72 @@
package commands
import (
"io/ioutil"
"time"
"fmt"
"github.com/spf13/cobra"
. "github.com/tendermint/go-common"
"github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/types"
nm "github.com/tendermint/tendermint/node"
)
var runNodeCmd = &cobra.Command{
Use: "node",
Short: "Run the tendermint node",
PreRun: setConfigFlags,
Run: runNode,
// AddNodeFlags exposes some common configuration options on the command-line
// These are exposed for convenience of commands embedding a tendermint node
func AddNodeFlags(cmd *cobra.Command) {
// bind flags
cmd.Flags().String("moniker", config.Moniker, "Node Name")
// priv val flags
cmd.Flags().String("priv_validator_laddr", config.PrivValidatorListenAddr, "Socket address to listen on for connections from external priv_validator process")
// node flags
cmd.Flags().Bool("fast_sync", config.FastSync, "Fast blockchain syncing")
// abci flags
cmd.Flags().String("proxy_app", config.ProxyApp, "Proxy app address, or 'nilapp' or 'kvstore' for local testing.")
cmd.Flags().String("abci", config.ABCI, "Specify abci transport (socket | grpc)")
// rpc flags
cmd.Flags().String("rpc.laddr", config.RPC.ListenAddress, "RPC listen address. Port required")
cmd.Flags().String("rpc.grpc_laddr", config.RPC.GRPCListenAddress, "GRPC listen address (BroadcastTx only). Port required")
cmd.Flags().Bool("rpc.unsafe", config.RPC.Unsafe, "Enabled unsafe rpc methods")
// p2p flags
cmd.Flags().String("p2p.laddr", config.P2P.ListenAddress, "Node listen address. (0.0.0.0:0 means any interface, any port)")
cmd.Flags().String("p2p.seeds", config.P2P.Seeds, "Comma-delimited ID@host:port seed nodes")
cmd.Flags().String("p2p.persistent_peers", config.P2P.PersistentPeers, "Comma-delimited ID@host:port persistent peers")
cmd.Flags().Bool("p2p.skip_upnp", config.P2P.SkipUPNP, "Skip UPNP configuration")
cmd.Flags().Bool("p2p.pex", config.P2P.PexReactor, "Enable/disable Peer-Exchange")
cmd.Flags().Bool("p2p.seed_mode", config.P2P.SeedMode, "Enable/disable seed mode")
cmd.Flags().String("p2p.private_peer_ids", config.P2P.PrivatePeerIDs, "Comma-delimited private peer IDs")
// consensus flags
cmd.Flags().Bool("consensus.create_empty_blocks", config.Consensus.CreateEmptyBlocks, "Set this to false to only produce blocks when there are txs or when the AppHash changes")
}
//flags
var (
moniker string
nodeLaddr string
seeds string
fastSync bool
skipUPNP bool
rpcLaddr string
grpcLaddr string
proxyApp string
abciTransport string
pex bool
)
func init() {
// configuration options
runNodeCmd.Flags().StringVar(&moniker, "moniker", config.GetString("moniker"),
"Node Name")
runNodeCmd.Flags().StringVar(&nodeLaddr, "node_laddr", config.GetString("node_laddr"),
"Node listen address. (0.0.0.0:0 means any interface, any port)")
runNodeCmd.Flags().StringVar(&seeds, "seeds", config.GetString("seeds"),
"Comma delimited host:port seed nodes")
runNodeCmd.Flags().BoolVar(&fastSync, "fast_sync", config.GetBool("fast_sync"),
"Fast blockchain syncing")
runNodeCmd.Flags().BoolVar(&skipUPNP, "skip_upnp", config.GetBool("skip_upnp"),
"Skip UPNP configuration")
runNodeCmd.Flags().StringVar(&rpcLaddr, "rpc_laddr", config.GetString("rpc_laddr"),
"RPC listen address. Port required")
runNodeCmd.Flags().StringVar(&grpcLaddr, "grpc_laddr", config.GetString("grpc_laddr"),
"GRPC listen address (BroadcastTx only). Port required")
runNodeCmd.Flags().StringVar(&proxyApp, "proxy_app", config.GetString("proxy_app"),
"Proxy app address, or 'nilapp' or 'dummy' for local testing.")
runNodeCmd.Flags().StringVar(&abciTransport, "abci", config.GetString("abci"),
"Specify abci transport (socket | grpc)")
// feature flags
runNodeCmd.Flags().BoolVar(&pex, "pex", config.GetBool("pex_reactor"),
"Enable Peer-Exchange (dev feature)")
RootCmd.AddCommand(runNodeCmd)
}
func setConfigFlags(cmd *cobra.Command, args []string) {
// Merge parsed flag values onto config
config.Set("moniker", moniker)
config.Set("node_laddr", nodeLaddr)
config.Set("seeds", seeds)
config.Set("fast_sync", fastSync)
config.Set("skip_upnp", skipUPNP)
config.Set("rpc_laddr", rpcLaddr)
config.Set("grpc_laddr", grpcLaddr)
config.Set("proxy_app", proxyApp)
config.Set("abci", abciTransport)
config.Set("pex_reactor", pex)
}
// Users wishing to:
// * Use an external signer for their validators
// * Supply an in-proc abci app
// should import github.com/tendermint/tendermint/node and implement
// their own run_node to call node.NewNode (instead of node.NewNodeDefault)
// with their custom priv validator and/or custom proxy.ClientCreator
func runNode(cmd *cobra.Command, args []string) {
// Wait until the genesis doc becomes available
// This is for Mintnet compatibility.
// TODO: If Mintnet gets deprecated or genesis_file is
// always available, remove.
genDocFile := config.GetString("genesis_file")
if !FileExists(genDocFile) {
log.Notice(Fmt("Waiting for genesis file %v...", genDocFile))
for {
time.Sleep(time.Second)
if !FileExists(genDocFile) {
continue
}
jsonBlob, err := ioutil.ReadFile(genDocFile)
// NewRunNodeCmd returns the command that allows the CLI to start a node.
// It can be used with a custom PrivValidator and in-process ABCI application.
func NewRunNodeCmd(nodeProvider nm.NodeProvider) *cobra.Command {
cmd := &cobra.Command{
Use: "node",
Short: "Run the tendermint node",
RunE: func(cmd *cobra.Command, args []string) error {
// Create & start node
n, err := nodeProvider(config, logger)
if err != nil {
Exit(Fmt("Couldn't read GenesisDoc file: %v", err))
return fmt.Errorf("Failed to create node: %v", err)
}
genDoc, err := types.GenesisDocFromJSON(jsonBlob)
if err != nil {
Exit(Fmt("Error reading GenesisDoc: %v", err))
if err := n.Start(); err != nil {
return fmt.Errorf("Failed to start node: %v", err)
}
if genDoc.ChainID == "" {
Exit(Fmt("Genesis doc %v must include non-empty chain_id", genDocFile))
}
config.Set("chain_id", genDoc.ChainID)
}
logger.Info("Started node", "nodeInfo", n.Switch().NodeInfo())
// Trap signal, run forever.
n.RunForever()
return nil
},
}
// Create & start node
n := node.NewNodeDefault(config)
if _, err := n.Start(); err != nil {
Exit(Fmt("Failed to start node: %v", err))
} else {
log.Notice("Started node", "nodeInfo", n.Switch().NodeInfo())
}
// Trap signal, run forever.
n.RunForever()
AddNodeFlags(cmd)
return cmd
}

View File

@ -0,0 +1,27 @@
package commands
import (
"fmt"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/p2p"
)
// ShowNodeIDCmd dumps node's ID to the standard output.
var ShowNodeIDCmd = &cobra.Command{
Use: "show_node_id",
Short: "Show this node's ID",
RunE: showNodeID,
}
func showNodeID(cmd *cobra.Command, args []string) error {
nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile())
if err != nil {
return err
}
fmt.Println(nodeKey.ID())
return nil
}

View File

@ -5,22 +5,18 @@ import (
"github.com/spf13/cobra"
"github.com/tendermint/go-wire"
"github.com/tendermint/tendermint/types"
privval "github.com/tendermint/tendermint/types/priv_validator"
)
var showValidatorCmd = &cobra.Command{
// ShowValidatorCmd adds capabilities for showing the validator info.
var ShowValidatorCmd = &cobra.Command{
Use: "show_validator",
Short: "Show this node's validator info",
Run: showValidator,
}
func init() {
RootCmd.AddCommand(showValidatorCmd)
}
func showValidator(cmd *cobra.Command, args []string) {
privValidatorFile := config.GetString("priv_validator_file")
privValidator := types.LoadOrGenPrivValidator(privValidatorFile)
fmt.Println(string(wire.JSONBytesPretty(privValidator.PubKey)))
privValidator := privval.LoadOrGenFilePV(config.PrivValidatorFile())
pubKeyJSONBytes, _ := cdc.MarshalJSON(privValidator.GetPubKey())
fmt.Println(string(pubKeyJSONBytes))
}

View File

@ -2,57 +2,103 @@ package commands
import (
"fmt"
"path"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/spf13/cobra"
cmn "github.com/tendermint/go-common"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
cmn "github.com/tendermint/tmlibs/common"
)
var testnetFilesCmd = &cobra.Command{
Use: "testnet",
Short: "Initialize files for a Tendermint testnet",
Run: testnetFiles,
}
//flags
var (
nValidators int
dataDir string
nValidators int
nNonValidators int
outputDir string
nodeDirPrefix string
populatePersistentPeers bool
hostnamePrefix string
startingIPAddress string
p2pPort int
)
const (
nodeDirPerm = 0755
)
func init() {
testnetFilesCmd.Flags().IntVar(&nValidators, "n", 4,
TestnetFilesCmd.Flags().IntVar(&nValidators, "v", 4,
"Number of validators to initialize the testnet with")
testnetFilesCmd.Flags().StringVar(&dataDir, "dir", "mytestnet",
TestnetFilesCmd.Flags().IntVar(&nNonValidators, "n", 0,
"Number of non-validators to initialize the testnet with")
TestnetFilesCmd.Flags().StringVar(&outputDir, "o", "./mytestnet",
"Directory to store initialization data for the testnet")
TestnetFilesCmd.Flags().StringVar(&nodeDirPrefix, "node-dir-prefix", "node",
"Prefix the directory name for each node with (node results in node0, node1, ...)")
RootCmd.AddCommand(testnetFilesCmd)
TestnetFilesCmd.Flags().BoolVar(&populatePersistentPeers, "populate-persistent-peers", true,
"Update config of each node with the list of persistent peers build using either hostname-prefix or starting-ip-address")
TestnetFilesCmd.Flags().StringVar(&hostnamePrefix, "hostname-prefix", "node",
"Hostname prefix (node results in persistent peers list ID0@node0:46656, ID1@node1:46656, ...)")
TestnetFilesCmd.Flags().StringVar(&startingIPAddress, "starting-ip-address", "",
"Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
TestnetFilesCmd.Flags().IntVar(&p2pPort, "p2p-port", 46656,
"P2P Port")
}
func testnetFiles(cmd *cobra.Command, args []string) {
// TestnetFilesCmd allows initialisation of files for a Tendermint testnet.
var TestnetFilesCmd = &cobra.Command{
Use: "testnet",
Short: "Initialize files for a Tendermint testnet",
RunE: testnetFiles,
}
func testnetFiles(cmd *cobra.Command, args []string) error {
config := cfg.DefaultConfig()
genVals := make([]types.GenesisValidator, nValidators)
// Initialize core dir and priv_validator.json's
for i := 0; i < nValidators; i++ {
mach := cmn.Fmt("mach%d", i)
err := initMachCoreDirectory(dataDir, mach)
nodeDirName := cmn.Fmt("%s%d", nodeDirPrefix, i)
nodeDir := filepath.Join(outputDir, nodeDirName)
config.SetRoot(nodeDir)
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm)
if err != nil {
cmn.Exit(err.Error())
_ = os.RemoveAll(outputDir)
return err
}
// Read priv_validator.json to populate vals
privValFile := path.Join(dataDir, mach, "priv_validator.json")
privVal := types.LoadPrivValidator(privValFile)
initFilesWithConfig(config)
pvFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidator)
pv := pvm.LoadFilePV(pvFile)
genVals[i] = types.GenesisValidator{
PubKey: privVal.PubKey,
Amount: 1,
Name: mach,
PubKey: pv.GetPubKey(),
Power: 1,
Name: nodeDirName,
}
}
for i := 0; i < nNonValidators; i++ {
nodeDir := filepath.Join(outputDir, cmn.Fmt("%s%d", nodeDirPrefix, i+nValidators))
config.SetRoot(nodeDir)
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm)
if err != nil {
_ = os.RemoveAll(outputDir)
return err
}
initFilesWithConfig(config)
}
// Generate genesis doc from generated validators
genDoc := &types.GenesisDoc{
GenesisTime: time.Now(),
@ -61,33 +107,65 @@ func testnetFiles(cmd *cobra.Command, args []string) {
}
// Write genesis file.
for i := 0; i < nValidators; i++ {
mach := cmn.Fmt("mach%d", i)
genDoc.SaveAs(path.Join(dataDir, mach, "genesis.json"))
for i := 0; i < nValidators+nNonValidators; i++ {
nodeDir := filepath.Join(outputDir, cmn.Fmt("%s%d", nodeDirPrefix, i))
if err := genDoc.SaveAs(filepath.Join(nodeDir, config.BaseConfig.Genesis)); err != nil {
_ = os.RemoveAll(outputDir)
return err
}
}
fmt.Println(cmn.Fmt("Successfully initialized %v node directories", nValidators))
}
// Initialize per-machine core directory
func initMachCoreDirectory(base, mach string) error {
dir := path.Join(base, mach)
err := cmn.EnsureDir(dir, 0777)
if err != nil {
return err
if populatePersistentPeers {
err := populatePersistentPeersInConfigAndWriteIt(config)
if err != nil {
_ = os.RemoveAll(outputDir)
return err
}
}
// Create priv_validator.json file if not present
ensurePrivValidator(path.Join(dir, "priv_validator.json"))
fmt.Printf("Successfully initialized %v node directories\n", nValidators+nNonValidators)
return nil
}
func ensurePrivValidator(file string) {
if cmn.FileExists(file) {
return
func hostnameOrIP(i int) string {
if startingIPAddress != "" {
ip := net.ParseIP(startingIPAddress)
ip = ip.To4()
if ip == nil {
fmt.Printf("%v: non ipv4 address\n", startingIPAddress)
os.Exit(1)
}
for j := 0; j < i; j++ {
ip[3]++
}
return ip.String()
}
privValidator := types.GenPrivValidator()
privValidator.SetFile(file)
privValidator.Save()
return fmt.Sprintf("%s%d", hostnamePrefix, i)
}
func populatePersistentPeersInConfigAndWriteIt(config *cfg.Config) error {
persistentPeers := make([]string, nValidators+nNonValidators)
for i := 0; i < nValidators+nNonValidators; i++ {
nodeDir := filepath.Join(outputDir, cmn.Fmt("%s%d", nodeDirPrefix, i))
config.SetRoot(nodeDir)
nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile())
if err != nil {
return err
}
persistentPeers[i] = p2p.IDAddressString(nodeKey.ID(), fmt.Sprintf("%s:%d", hostnameOrIP(i), p2pPort))
}
persistentPeersList := strings.Join(persistentPeers, ",")
for i := 0; i < nValidators+nNonValidators; i++ {
nodeDir := filepath.Join(outputDir, cmn.Fmt("%s%d", nodeDirPrefix, i))
config.SetRoot(nodeDir)
config.P2P.PersistentPeers = persistentPeersList
// overwrite default config
cfg.WriteConfigFile(filepath.Join(nodeDir, "config", "config.toml"), config)
}
return nil
}

View File

@ -8,14 +8,11 @@ import (
"github.com/tendermint/tendermint/version"
)
var versionCmd = &cobra.Command{
// VersionCmd ...
var VersionCmd = &cobra.Command{
Use: "version",
Short: "Show version info",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(version.Version)
},
}
func init() {
RootCmd.AddCommand(versionCmd)
}

View File

@ -0,0 +1,12 @@
package commands
import (
amino "github.com/tendermint/go-amino"
"github.com/tendermint/go-crypto"
)
var cdc = amino.NewCodec()
func init() {
crypto.RegisterAmino(cdc)
}

View File

@ -1,15 +1,48 @@
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tmlibs/cli"
cmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
cfg "github.com/tendermint/tendermint/config"
nm "github.com/tendermint/tendermint/node"
)
func main() {
if err := commands.RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
rootCmd := cmd.RootCmd
rootCmd.AddCommand(
cmd.GenValidatorCmd,
cmd.InitFilesCmd,
cmd.ProbeUpnpCmd,
cmd.LiteCmd,
cmd.ReplayCmd,
cmd.ReplayConsoleCmd,
cmd.ResetAllCmd,
cmd.ResetPrivValidatorCmd,
cmd.ShowValidatorCmd,
cmd.TestnetFilesCmd,
cmd.ShowNodeIDCmd,
cmd.GenNodeKeyCmd,
cmd.VersionCmd)
// NOTE:
// Users wishing to:
// * Use an external signer for their validators
// * Supply an in-proc abci app
// * Supply a genesis doc file from another source
// * Provide their own DB implementation
// can copy this file and use something other than the
// DefaultNewNode function
nodeFunc := nm.DefaultNewNode
// Create & start node
rootCmd.AddCommand(cmd.NewRunNodeCmd(nodeFunc))
cmd := cli.PrepareBaseCmd(rootCmd, "TM", os.ExpandEnv(filepath.Join("$HOME", cfg.DefaultTendermintDir)))
if err := cmd.Execute(); err != nil {
panic(err)
}
}

23
codecov.yml Normal file
View File

@ -0,0 +1,23 @@
coverage:
precision: 2
round: down
range: "70...100"
status:
project:
default:
threshold: 1%
patch: on
changes: off
comment:
layout: "diff, files"
behavior: default
require_changes: no
require_base: no
require_head: yes
ignore:
- "docs"
- "DOCKER"
- "scripts"

555
config/config.go Normal file
View File

@ -0,0 +1,555 @@
package config
import (
"fmt"
"os"
"path/filepath"
"time"
)
// NOTE: Most of the structs & relevant comments + the
// default configuration options were used to manually
// generate the config.toml. Please reflect any changes
// made here in the defaultConfigTemplate constant in
// config/toml.go
// NOTE: tmlibs/cli must know to look in the config dir!
var (
DefaultTendermintDir = ".tendermint"
defaultConfigDir = "config"
defaultDataDir = "data"
defaultConfigFileName = "config.toml"
defaultGenesisJSONName = "genesis.json"
defaultPrivValName = "priv_validator.json"
defaultNodeKeyName = "node_key.json"
defaultAddrBookName = "addrbook.json"
defaultConfigFilePath = filepath.Join(defaultConfigDir, defaultConfigFileName)
defaultGenesisJSONPath = filepath.Join(defaultConfigDir, defaultGenesisJSONName)
defaultPrivValPath = filepath.Join(defaultConfigDir, defaultPrivValName)
defaultNodeKeyPath = filepath.Join(defaultConfigDir, defaultNodeKeyName)
defaultAddrBookPath = filepath.Join(defaultConfigDir, defaultAddrBookName)
)
// Config defines the top level configuration for a Tendermint node
type Config struct {
// Top level options use an anonymous struct
BaseConfig `mapstructure:",squash"`
// Options for services
RPC *RPCConfig `mapstructure:"rpc"`
P2P *P2PConfig `mapstructure:"p2p"`
Mempool *MempoolConfig `mapstructure:"mempool"`
Consensus *ConsensusConfig `mapstructure:"consensus"`
TxIndex *TxIndexConfig `mapstructure:"tx_index"`
}
// DefaultConfig returns a default configuration for a Tendermint node
func DefaultConfig() *Config {
return &Config{
BaseConfig: DefaultBaseConfig(),
RPC: DefaultRPCConfig(),
P2P: DefaultP2PConfig(),
Mempool: DefaultMempoolConfig(),
Consensus: DefaultConsensusConfig(),
TxIndex: DefaultTxIndexConfig(),
}
}
// TestConfig returns a configuration that can be used for testing
func TestConfig() *Config {
return &Config{
BaseConfig: TestBaseConfig(),
RPC: TestRPCConfig(),
P2P: TestP2PConfig(),
Mempool: TestMempoolConfig(),
Consensus: TestConsensusConfig(),
TxIndex: TestTxIndexConfig(),
}
}
// SetRoot sets the RootDir for all Config structs
func (cfg *Config) SetRoot(root string) *Config {
cfg.BaseConfig.RootDir = root
cfg.RPC.RootDir = root
cfg.P2P.RootDir = root
cfg.Mempool.RootDir = root
cfg.Consensus.RootDir = root
return cfg
}
//-----------------------------------------------------------------------------
// BaseConfig
// BaseConfig defines the base configuration for a Tendermint node
type BaseConfig struct {
// chainID is unexposed and immutable but here for convenience
chainID string
// The root directory for all data.
// This should be set in viper so it can unmarshal into this struct
RootDir string `mapstructure:"home"`
// Path to the JSON file containing the initial validator set and other meta data
Genesis string `mapstructure:"genesis_file"`
// Path to the JSON file containing the private key to use as a validator in the consensus protocol
PrivValidator string `mapstructure:"priv_validator_file"`
// A JSON file containing the private key to use for p2p authenticated encryption
NodeKey string `mapstructure:"node_key_file"`
// A custom human readable name for this node
Moniker string `mapstructure:"moniker"`
// TCP or UNIX socket address for Tendermint to listen on for
// connections from an external PrivValidator process
PrivValidatorListenAddr string `mapstructure:"priv_validator_laddr"`
// TCP or UNIX socket address of the ABCI application,
// or the name of an ABCI application compiled in with the Tendermint binary
ProxyApp string `mapstructure:"proxy_app"`
// Mechanism to connect to the ABCI application: socket | grpc
ABCI string `mapstructure:"abci"`
// Output level for logging
LogLevel string `mapstructure:"log_level"`
// TCP or UNIX socket address for the profiling server to listen on
ProfListenAddress string `mapstructure:"prof_laddr"`
// If this node is many blocks behind the tip of the chain, FastSync
// allows them to catchup quickly by downloading blocks in parallel
// and verifying their commits
FastSync bool `mapstructure:"fast_sync"`
// If true, query the ABCI app on connecting to a new peer
// so the app can decide if we should keep the connection or not
FilterPeers bool `mapstructure:"filter_peers"` // false
// Database backend: leveldb | memdb
DBBackend string `mapstructure:"db_backend"`
// Database directory
DBPath string `mapstructure:"db_dir"`
}
// DefaultBaseConfig returns a default base configuration for a Tendermint node
func DefaultBaseConfig() BaseConfig {
return BaseConfig{
Genesis: defaultGenesisJSONPath,
PrivValidator: defaultPrivValPath,
NodeKey: defaultNodeKeyPath,
Moniker: defaultMoniker,
ProxyApp: "tcp://127.0.0.1:46658",
ABCI: "socket",
LogLevel: DefaultPackageLogLevels(),
ProfListenAddress: "",
FastSync: true,
FilterPeers: false,
DBBackend: "leveldb",
DBPath: "data",
}
}
// TestBaseConfig returns a base configuration for testing a Tendermint node
func TestBaseConfig() BaseConfig {
cfg := DefaultBaseConfig()
cfg.chainID = "tendermint_test"
cfg.ProxyApp = "kvstore"
cfg.FastSync = false
cfg.DBBackend = "memdb"
return cfg
}
func (cfg BaseConfig) ChainID() string {
return cfg.chainID
}
// GenesisFile returns the full path to the genesis.json file
func (cfg BaseConfig) GenesisFile() string {
return rootify(cfg.Genesis, cfg.RootDir)
}
// PrivValidatorFile returns the full path to the priv_validator.json file
func (cfg BaseConfig) PrivValidatorFile() string {
return rootify(cfg.PrivValidator, cfg.RootDir)
}
// NodeKeyFile returns the full path to the node_key.json file
func (cfg BaseConfig) NodeKeyFile() string {
return rootify(cfg.NodeKey, cfg.RootDir)
}
// DBDir returns the full path to the database directory
func (cfg BaseConfig) DBDir() string {
return rootify(cfg.DBPath, cfg.RootDir)
}
// DefaultLogLevel returns a default log level of "error"
func DefaultLogLevel() string {
return "error"
}
// DefaultPackageLogLevels returns a default log level setting so all packages
// log at "error", while the `state` and `main` packages log at "info"
func DefaultPackageLogLevels() string {
return fmt.Sprintf("main:info,state:info,*:%s", DefaultLogLevel())
}
//-----------------------------------------------------------------------------
// RPCConfig
// RPCConfig defines the configuration options for the Tendermint RPC server
type RPCConfig struct {
RootDir string `mapstructure:"home"`
// TCP or UNIX socket address for the RPC server to listen on
ListenAddress string `mapstructure:"laddr"`
// TCP or UNIX socket address for the gRPC server to listen on
// NOTE: This server only supports /broadcast_tx_commit
GRPCListenAddress string `mapstructure:"grpc_laddr"`
// Activate unsafe RPC commands like /dial_persistent_peers and /unsafe_flush_mempool
Unsafe bool `mapstructure:"unsafe"`
}
// DefaultRPCConfig returns a default configuration for the RPC server
func DefaultRPCConfig() *RPCConfig {
return &RPCConfig{
ListenAddress: "tcp://0.0.0.0:46657",
GRPCListenAddress: "",
Unsafe: false,
}
}
// TestRPCConfig returns a configuration for testing the RPC server
func TestRPCConfig() *RPCConfig {
cfg := DefaultRPCConfig()
cfg.ListenAddress = "tcp://0.0.0.0:36657"
cfg.GRPCListenAddress = "tcp://0.0.0.0:36658"
cfg.Unsafe = true
return cfg
}
//-----------------------------------------------------------------------------
// P2PConfig
// P2PConfig defines the configuration options for the Tendermint peer-to-peer networking layer
type P2PConfig struct {
RootDir string `mapstructure:"home"`
// Address to listen for incoming connections
ListenAddress string `mapstructure:"laddr"`
// Comma separated list of seed nodes to connect to
// We only use these if we cant connect to peers in the addrbook
Seeds string `mapstructure:"seeds"`
// Comma separated list of nodes to keep persistent connections to
// Do not add private peers to this list if you don't want them advertised
PersistentPeers string `mapstructure:"persistent_peers"`
// Skip UPNP port forwarding
SkipUPNP bool `mapstructure:"skip_upnp"`
// Path to address book
AddrBook string `mapstructure:"addr_book_file"`
// Set true for strict address routability rules
AddrBookStrict bool `mapstructure:"addr_book_strict"`
// Maximum number of peers to connect to
MaxNumPeers int `mapstructure:"max_num_peers"`
// Time to wait before flushing messages out on the connection, in ms
FlushThrottleTimeout int `mapstructure:"flush_throttle_timeout"`
// Maximum size of a message packet payload, in bytes
MaxPacketMsgPayloadSize int `mapstructure:"max_packet_msg_payload_size"`
// Rate at which packets can be sent, in bytes/second
SendRate int64 `mapstructure:"send_rate"`
// Rate at which packets can be received, in bytes/second
RecvRate int64 `mapstructure:"recv_rate"`
// Set true to enable the peer-exchange reactor
PexReactor bool `mapstructure:"pex"`
// Seed mode, in which node constantly crawls the network and looks for
// peers. If another node asks it for addresses, it responds and disconnects.
//
// Does not work if the peer-exchange reactor is disabled.
SeedMode bool `mapstructure:"seed_mode"`
// Authenticated encryption
AuthEnc bool `mapstructure:"auth_enc"`
// Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
PrivatePeerIDs string `mapstructure:"private_peer_ids"`
}
// DefaultP2PConfig returns a default configuration for the peer-to-peer layer
func DefaultP2PConfig() *P2PConfig {
return &P2PConfig{
ListenAddress: "tcp://0.0.0.0:46656",
AddrBook: defaultAddrBookPath,
AddrBookStrict: true,
MaxNumPeers: 50,
FlushThrottleTimeout: 100,
MaxPacketMsgPayloadSize: 1024, // 1 kB
SendRate: 512000, // 500 kB/s
RecvRate: 512000, // 500 kB/s
PexReactor: true,
SeedMode: false,
AuthEnc: true,
}
}
// TestP2PConfig returns a configuration for testing the peer-to-peer layer
func TestP2PConfig() *P2PConfig {
cfg := DefaultP2PConfig()
cfg.ListenAddress = "tcp://0.0.0.0:36656"
cfg.SkipUPNP = true
cfg.FlushThrottleTimeout = 10
return cfg
}
// AddrBookFile returns the full path to the address book
func (cfg *P2PConfig) AddrBookFile() string {
return rootify(cfg.AddrBook, cfg.RootDir)
}
//-----------------------------------------------------------------------------
// MempoolConfig
// MempoolConfig defines the configuration options for the Tendermint mempool
type MempoolConfig struct {
RootDir string `mapstructure:"home"`
Recheck bool `mapstructure:"recheck"`
RecheckEmpty bool `mapstructure:"recheck_empty"`
Broadcast bool `mapstructure:"broadcast"`
WalPath string `mapstructure:"wal_dir"`
CacheSize int `mapstructure:"cache_size"`
}
// DefaultMempoolConfig returns a default configuration for the Tendermint mempool
func DefaultMempoolConfig() *MempoolConfig {
return &MempoolConfig{
Recheck: true,
RecheckEmpty: true,
Broadcast: true,
WalPath: filepath.Join(defaultDataDir, "mempool.wal"),
CacheSize: 100000,
}
}
// TestMempoolConfig returns a configuration for testing the Tendermint mempool
func TestMempoolConfig() *MempoolConfig {
cfg := DefaultMempoolConfig()
cfg.CacheSize = 1000
return cfg
}
// WalDir returns the full path to the mempool's write-ahead log
func (cfg *MempoolConfig) WalDir() string {
return rootify(cfg.WalPath, cfg.RootDir)
}
//-----------------------------------------------------------------------------
// ConsensusConfig
// ConsensusConfig defines the confuguration for the Tendermint consensus service,
// including timeouts and details about the WAL and the block structure.
type ConsensusConfig struct {
RootDir string `mapstructure:"home"`
WalPath string `mapstructure:"wal_file"`
WalLight bool `mapstructure:"wal_light"`
walFile string // overrides WalPath if set
// All timeouts are in milliseconds
TimeoutPropose int `mapstructure:"timeout_propose"`
TimeoutProposeDelta int `mapstructure:"timeout_propose_delta"`
TimeoutPrevote int `mapstructure:"timeout_prevote"`
TimeoutPrevoteDelta int `mapstructure:"timeout_prevote_delta"`
TimeoutPrecommit int `mapstructure:"timeout_precommit"`
TimeoutPrecommitDelta int `mapstructure:"timeout_precommit_delta"`
TimeoutCommit int `mapstructure:"timeout_commit"`
// Make progress as soon as we have all the precommits (as if TimeoutCommit = 0)
SkipTimeoutCommit bool `mapstructure:"skip_timeout_commit"`
// BlockSize
MaxBlockSizeTxs int `mapstructure:"max_block_size_txs"`
MaxBlockSizeBytes int `mapstructure:"max_block_size_bytes"`
// EmptyBlocks mode and possible interval between empty blocks in seconds
CreateEmptyBlocks bool `mapstructure:"create_empty_blocks"`
CreateEmptyBlocksInterval int `mapstructure:"create_empty_blocks_interval"`
// Reactor sleep duration parameters are in milliseconds
PeerGossipSleepDuration int `mapstructure:"peer_gossip_sleep_duration"`
PeerQueryMaj23SleepDuration int `mapstructure:"peer_query_maj23_sleep_duration"`
}
// DefaultConsensusConfig returns a default configuration for the consensus service
func DefaultConsensusConfig() *ConsensusConfig {
return &ConsensusConfig{
WalPath: filepath.Join(defaultDataDir, "cs.wal", "wal"),
WalLight: false,
TimeoutPropose: 3000,
TimeoutProposeDelta: 500,
TimeoutPrevote: 1000,
TimeoutPrevoteDelta: 500,
TimeoutPrecommit: 1000,
TimeoutPrecommitDelta: 500,
TimeoutCommit: 1000,
SkipTimeoutCommit: false,
MaxBlockSizeTxs: 10000,
MaxBlockSizeBytes: 1, // TODO
CreateEmptyBlocks: true,
CreateEmptyBlocksInterval: 0,
PeerGossipSleepDuration: 100,
PeerQueryMaj23SleepDuration: 2000,
}
}
// TestConsensusConfig returns a configuration for testing the consensus service
func TestConsensusConfig() *ConsensusConfig {
cfg := DefaultConsensusConfig()
cfg.TimeoutPropose = 100
cfg.TimeoutProposeDelta = 1
cfg.TimeoutPrevote = 10
cfg.TimeoutPrevoteDelta = 1
cfg.TimeoutPrecommit = 10
cfg.TimeoutPrecommitDelta = 1
cfg.TimeoutCommit = 10
cfg.SkipTimeoutCommit = true
cfg.PeerGossipSleepDuration = 5
cfg.PeerQueryMaj23SleepDuration = 250
return cfg
}
// WaitForTxs returns true if the consensus should wait for transactions before entering the propose step
func (cfg *ConsensusConfig) WaitForTxs() bool {
return !cfg.CreateEmptyBlocks || cfg.CreateEmptyBlocksInterval > 0
}
// EmptyBlocks returns the amount of time to wait before proposing an empty block or starting the propose timer if there are no txs available
func (cfg *ConsensusConfig) EmptyBlocksInterval() time.Duration {
return time.Duration(cfg.CreateEmptyBlocksInterval) * time.Second
}
// Propose returns the amount of time to wait for a proposal
func (cfg *ConsensusConfig) Propose(round int) time.Duration {
return time.Duration(cfg.TimeoutPropose+cfg.TimeoutProposeDelta*round) * time.Millisecond
}
// Prevote returns the amount of time to wait for straggler votes after receiving any +2/3 prevotes
func (cfg *ConsensusConfig) Prevote(round int) time.Duration {
return time.Duration(cfg.TimeoutPrevote+cfg.TimeoutPrevoteDelta*round) * time.Millisecond
}
// Precommit returns the amount of time to wait for straggler votes after receiving any +2/3 precommits
func (cfg *ConsensusConfig) Precommit(round int) time.Duration {
return time.Duration(cfg.TimeoutPrecommit+cfg.TimeoutPrecommitDelta*round) * time.Millisecond
}
// Commit returns the amount of time to wait for straggler votes after receiving +2/3 precommits for a single block (ie. a commit).
func (cfg *ConsensusConfig) Commit(t time.Time) time.Time {
return t.Add(time.Duration(cfg.TimeoutCommit) * time.Millisecond)
}
// PeerGossipSleep returns the amount of time to sleep if there is nothing to send from the ConsensusReactor
func (cfg *ConsensusConfig) PeerGossipSleep() time.Duration {
return time.Duration(cfg.PeerGossipSleepDuration) * time.Millisecond
}
// PeerQueryMaj23Sleep returns the amount of time to sleep after each VoteSetMaj23Message is sent in the ConsensusReactor
func (cfg *ConsensusConfig) PeerQueryMaj23Sleep() time.Duration {
return time.Duration(cfg.PeerQueryMaj23SleepDuration) * time.Millisecond
}
// WalFile returns the full path to the write-ahead log file
func (cfg *ConsensusConfig) WalFile() string {
if cfg.walFile != "" {
return cfg.walFile
}
return rootify(cfg.WalPath, cfg.RootDir)
}
// SetWalFile sets the path to the write-ahead log file
func (cfg *ConsensusConfig) SetWalFile(walFile string) {
cfg.walFile = walFile
}
//-----------------------------------------------------------------------------
// TxIndexConfig
// TxIndexConfig defines the confuguration for the transaction
// indexer, including tags to index.
type TxIndexConfig struct {
// What indexer to use for transactions
//
// Options:
// 1) "null" (default)
// 2) "kv" - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
Indexer string `mapstructure:"indexer"`
// Comma-separated list of tags to index (by default the only tag is tx hash)
//
// It's recommended to index only a subset of tags due to possible memory
// bloat. This is, of course, depends on the indexer's DB and the volume of
// transactions.
IndexTags string `mapstructure:"index_tags"`
// When set to true, tells indexer to index all tags. Note this may be not
// desirable (see the comment above). IndexTags has a precedence over
// IndexAllTags (i.e. when given both, IndexTags will be indexed).
IndexAllTags bool `mapstructure:"index_all_tags"`
}
// DefaultTxIndexConfig returns a default configuration for the transaction indexer.
func DefaultTxIndexConfig() *TxIndexConfig {
return &TxIndexConfig{
Indexer: "kv",
IndexTags: "",
IndexAllTags: false,
}
}
// TestTxIndexConfig returns a default configuration for the transaction indexer.
func TestTxIndexConfig() *TxIndexConfig {
return DefaultTxIndexConfig()
}
//-----------------------------------------------------------------------------
// Utils
// helper function to make config creation independent of root dir
func rootify(path, root string) string {
if filepath.IsAbs(path) {
return path
}
return filepath.Join(root, path)
}
//-----------------------------------------------------------------------------
// Moniker
var defaultMoniker = getDefaultMoniker()
// getDefaultMoniker returns a default moniker, which is the host name. If runtime
// fails to get the host name, "anonymous" will be returned.
func getDefaultMoniker() string {
moniker, err := os.Hostname()
if err != nil {
moniker = "anonymous"
}
return moniker
}

28
config/config_test.go Normal file
View File

@ -0,0 +1,28 @@
package config
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDefaultConfig(t *testing.T) {
assert := assert.New(t)
// set up some defaults
cfg := DefaultConfig()
assert.NotNil(cfg.P2P)
assert.NotNil(cfg.Mempool)
assert.NotNil(cfg.Consensus)
// check the root dir stuff...
cfg.SetRoot("/foo")
cfg.Genesis = "bar"
cfg.DBPath = "/opt/data"
cfg.Mempool.WalPath = "wal/mem/"
assert.Equal("/foo/bar", cfg.GenesisFile())
assert.Equal("/opt/data", cfg.DBDir())
assert.Equal("/foo/wal/mem", cfg.Mempool.WalDir())
}

View File

@ -1,125 +0,0 @@
package tendermint
import (
"os"
"path"
"strings"
. "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
)
func getTMRoot(rootDir string) string {
if rootDir == "" {
rootDir = os.Getenv("TMHOME")
}
if rootDir == "" {
// deprecated, use TMHOME (TODO: remove in TM 0.11.0)
rootDir = os.Getenv("TMROOT")
}
if rootDir == "" {
rootDir = os.Getenv("HOME") + "/.tendermint"
}
return rootDir
}
func initTMRoot(rootDir string) {
rootDir = getTMRoot(rootDir)
EnsureDir(rootDir, 0700)
EnsureDir(rootDir+"/data", 0700)
configFilePath := path.Join(rootDir, "config.toml")
// Write default config file if missing.
if !FileExists(configFilePath) {
// Ask user for moniker
// moniker := cfg.Prompt("Type hostname: ", "anonymous")
MustWriteFile(configFilePath, []byte(defaultConfig("anonymous")), 0644)
}
}
func GetConfig(rootDir string) cfg.Config {
rootDir = getTMRoot(rootDir)
initTMRoot(rootDir)
configFilePath := path.Join(rootDir, "config.toml")
mapConfig, err := cfg.ReadMapConfigFromFile(configFilePath)
if err != nil {
Exit(Fmt("Could not read config: %v", err))
}
// Set defaults or panic
if mapConfig.IsSet("chain_id") {
Exit("Cannot set 'chain_id' via config.toml")
}
if mapConfig.IsSet("revision_file") {
Exit("Cannot set 'revision_file' via config.toml. It must match what's in the Makefile")
}
mapConfig.SetRequired("chain_id") // blows up if you try to use it before setting.
mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
mapConfig.SetDefault("proxy_app", "tcp://127.0.0.1:46658")
mapConfig.SetDefault("abci", "socket")
mapConfig.SetDefault("moniker", "anonymous")
mapConfig.SetDefault("node_laddr", "tcp://0.0.0.0:46656")
mapConfig.SetDefault("seeds", "")
// mapConfig.SetDefault("seeds", "goldenalchemist.chaintest.net:46656")
mapConfig.SetDefault("fast_sync", true)
mapConfig.SetDefault("skip_upnp", false)
mapConfig.SetDefault("addrbook_file", rootDir+"/addrbook.json")
mapConfig.SetDefault("addrbook_strict", true) // disable to allow connections locally
mapConfig.SetDefault("pex_reactor", false) // enable for peer exchange
mapConfig.SetDefault("priv_validator_file", rootDir+"/priv_validator.json")
mapConfig.SetDefault("db_backend", "leveldb")
mapConfig.SetDefault("db_dir", rootDir+"/data")
mapConfig.SetDefault("log_level", "info")
mapConfig.SetDefault("rpc_laddr", "tcp://0.0.0.0:46657")
mapConfig.SetDefault("grpc_laddr", "")
mapConfig.SetDefault("prof_laddr", "")
mapConfig.SetDefault("revision_file", rootDir+"/revision")
mapConfig.SetDefault("cs_wal_file", rootDir+"/data/cs.wal/wal")
mapConfig.SetDefault("cs_wal_light", false)
mapConfig.SetDefault("filter_peers", false)
mapConfig.SetDefault("block_size", 10000) // max number of txs
mapConfig.SetDefault("block_part_size", 65536) // part size 64K
mapConfig.SetDefault("disable_data_hash", false)
// all timeouts are in ms
mapConfig.SetDefault("timeout_handshake", 10000)
mapConfig.SetDefault("timeout_propose", 3000)
mapConfig.SetDefault("timeout_propose_delta", 500)
mapConfig.SetDefault("timeout_prevote", 1000)
mapConfig.SetDefault("timeout_prevote_delta", 500)
mapConfig.SetDefault("timeout_precommit", 1000)
mapConfig.SetDefault("timeout_precommit_delta", 500)
mapConfig.SetDefault("timeout_commit", 1000)
// make progress asap (no `timeout_commit`) on full precommit votes
mapConfig.SetDefault("skip_timeout_commit", false)
mapConfig.SetDefault("mempool_recheck", true)
mapConfig.SetDefault("mempool_recheck_empty", true)
mapConfig.SetDefault("mempool_broadcast", true)
mapConfig.SetDefault("mempool_wal_dir", rootDir+"/data/mempool.wal")
mapConfig.SetDefault("tx_index", "kv")
return mapConfig
}
var defaultConfigTmpl = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
proxy_app = "tcp://127.0.0.1:46658"
moniker = "__MONIKER__"
node_laddr = "tcp://0.0.0.0:46656"
seeds = ""
fast_sync = true
db_backend = "leveldb"
log_level = "notice"
rpc_laddr = "tcp://0.0.0.0:46657"
`
func defaultConfig(moniker string) (defaultConfig string) {
defaultConfig = strings.Replace(defaultConfigTmpl, "__MONIKER__", moniker, -1)
return
}

View File

@ -1,22 +0,0 @@
// If you wanted to use logrotate, I suppose this might be the config you want.
// Instead, I'll just write our own, that way we don't need sudo to install.
$HOME/.tendermint/logs/tendermint.log {
missingok
notifempty
rotate 12
daily
size 10M
compress
delaycompress
}
$HOME/.barak/logs/barak.log {
missingok
notifempty
rotate 12
weekly
size 10M
compress
delaycompress
}

View File

@ -1,164 +0,0 @@
// Import this in all *_test.go files to initialize ~/.tendermint_test.
package tendermint_test
import (
"os"
"path"
"strings"
. "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
"github.com/tendermint/go-logger"
)
func init() {
// Creates ~/.tendermint_test
EnsureDir(os.Getenv("HOME")+"/.tendermint_test", 0700)
}
func initTMRoot(rootDir string) {
// Remove ~/.tendermint_test_bak
if FileExists(rootDir + "_bak") {
err := os.RemoveAll(rootDir + "_bak")
if err != nil {
PanicSanity(err.Error())
}
}
// Move ~/.tendermint_test to ~/.tendermint_test_bak
if FileExists(rootDir) {
err := os.Rename(rootDir, rootDir+"_bak")
if err != nil {
PanicSanity(err.Error())
}
}
// Create new dir
EnsureDir(rootDir, 0700)
EnsureDir(rootDir+"/data", 0700)
configFilePath := path.Join(rootDir, "config.toml")
genesisFilePath := path.Join(rootDir, "genesis.json")
privFilePath := path.Join(rootDir, "priv_validator.json")
// Write default config file if missing.
if !FileExists(configFilePath) {
// Ask user for moniker
// moniker := cfg.Prompt("Type hostname: ", "anonymous")
MustWriteFile(configFilePath, []byte(defaultConfig("anonymous")), 0644)
}
if !FileExists(genesisFilePath) {
MustWriteFile(genesisFilePath, []byte(defaultGenesis), 0644)
}
// we always overwrite the priv val
MustWriteFile(privFilePath, []byte(defaultPrivValidator), 0644)
}
func ResetConfig(localPath string) cfg.Config {
rootDir := os.Getenv("HOME") + "/.tendermint_test/" + localPath
initTMRoot(rootDir)
configFilePath := path.Join(rootDir, "config.toml")
mapConfig, err := cfg.ReadMapConfigFromFile(configFilePath)
if err != nil {
Exit(Fmt("Could not read config: %v", err))
}
// Set defaults or panic
if mapConfig.IsSet("chain_id") {
Exit("Cannot set 'chain_id' via config.toml")
}
mapConfig.SetDefault("chain_id", "tendermint_test")
mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
mapConfig.SetDefault("proxy_app", "dummy")
mapConfig.SetDefault("abci", "socket")
mapConfig.SetDefault("moniker", "anonymous")
mapConfig.SetDefault("node_laddr", "tcp://0.0.0.0:36656")
mapConfig.SetDefault("fast_sync", false)
mapConfig.SetDefault("skip_upnp", true)
mapConfig.SetDefault("addrbook_file", rootDir+"/addrbook.json")
mapConfig.SetDefault("addrbook_strict", true) // disable to allow connections locally
mapConfig.SetDefault("pex_reactor", false) // enable for peer exchange
mapConfig.SetDefault("priv_validator_file", rootDir+"/priv_validator.json")
mapConfig.SetDefault("db_backend", "memdb")
mapConfig.SetDefault("db_dir", rootDir+"/data")
mapConfig.SetDefault("log_level", "info")
mapConfig.SetDefault("rpc_laddr", "tcp://0.0.0.0:36657")
mapConfig.SetDefault("grpc_laddr", "tcp://0.0.0.0:36658")
mapConfig.SetDefault("prof_laddr", "")
mapConfig.SetDefault("revision_file", rootDir+"/revision")
mapConfig.SetDefault("cs_wal_file", rootDir+"/data/cs.wal/wal")
mapConfig.SetDefault("cs_wal_light", false)
mapConfig.SetDefault("filter_peers", false)
mapConfig.SetDefault("block_size", 10000)
mapConfig.SetDefault("block_part_size", 65536) // part size 64K
mapConfig.SetDefault("disable_data_hash", false)
mapConfig.SetDefault("timeout_handshake", 10000)
mapConfig.SetDefault("timeout_propose", 2000)
mapConfig.SetDefault("timeout_propose_delta", 1)
mapConfig.SetDefault("timeout_prevote", 10)
mapConfig.SetDefault("timeout_prevote_delta", 1)
mapConfig.SetDefault("timeout_precommit", 10)
mapConfig.SetDefault("timeout_precommit_delta", 1)
mapConfig.SetDefault("timeout_commit", 10)
mapConfig.SetDefault("skip_timeout_commit", true)
mapConfig.SetDefault("mempool_recheck", true)
mapConfig.SetDefault("mempool_recheck_empty", true)
mapConfig.SetDefault("mempool_broadcast", true)
mapConfig.SetDefault("mempool_wal_dir", "")
mapConfig.SetDefault("tx_index", "kv")
logger.SetLogLevel(mapConfig.GetString("log_level"))
return mapConfig
}
var defaultConfigTmpl = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
proxy_app = "dummy"
moniker = "__MONIKER__"
node_laddr = "tcp://0.0.0.0:36656"
seeds = ""
fast_sync = false
db_backend = "memdb"
log_level = "info"
rpc_laddr = "tcp://0.0.0.0:36657"
`
func defaultConfig(moniker string) (defaultConfig string) {
defaultConfig = strings.Replace(defaultConfigTmpl, "__MONIKER__", moniker, -1)
return
}
var defaultGenesis = `{
"genesis_time": "0001-01-01T00:00:00.000Z",
"chain_id": "tendermint_test",
"validators": [
{
"pub_key": [
1,
"3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
],
"amount": 10,
"name": ""
}
],
"app_hash": ""
}`
var defaultPrivValidator = `{
"address": "D028C9981F7A87F3093672BF0D5B0E2A1B3ED456",
"pub_key": [
1,
"3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
],
"priv_key": [
1,
"27F82582AEFAE7AB151CFB01C48BB6C1A0DA78F9BDDA979A9F70A84D074EB07D3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
],
"last_height": 0,
"last_round": 0,
"last_step": 0
}`

311
config/toml.go Normal file
View File

@ -0,0 +1,311 @@
package config
import (
"bytes"
"os"
"path/filepath"
"text/template"
cmn "github.com/tendermint/tmlibs/common"
)
var configTemplate *template.Template
func init() {
var err error
if configTemplate, err = template.New("configFileTemplate").Parse(defaultConfigTemplate); err != nil {
panic(err)
}
}
/****** these are for production settings ***********/
// EnsureRoot creates the root, config, and data directories if they don't exist,
// and panics if it fails.
func EnsureRoot(rootDir string) {
if err := cmn.EnsureDir(rootDir, 0700); err != nil {
cmn.PanicSanity(err.Error())
}
if err := cmn.EnsureDir(filepath.Join(rootDir, defaultConfigDir), 0700); err != nil {
cmn.PanicSanity(err.Error())
}
if err := cmn.EnsureDir(filepath.Join(rootDir, defaultDataDir), 0700); err != nil {
cmn.PanicSanity(err.Error())
}
configFilePath := filepath.Join(rootDir, defaultConfigFilePath)
// Write default config file if missing.
if !cmn.FileExists(configFilePath) {
writeDefaultCondigFile(configFilePath)
}
}
// XXX: this func should probably be called by cmd/tendermint/commands/init.go
// alongside the writing of the genesis.json and priv_validator.json
func writeDefaultCondigFile(configFilePath string) {
WriteConfigFile(configFilePath, DefaultConfig())
}
// WriteConfigFile renders config using the template and writes it to configFilePath.
func WriteConfigFile(configFilePath string, config *Config) {
var buffer bytes.Buffer
if err := configTemplate.Execute(&buffer, config); err != nil {
panic(err)
}
cmn.MustWriteFile(configFilePath, buffer.Bytes(), 0644)
}
// Note: any changes to the comments/variables/mapstructure
// must be reflected in the appropriate struct in config/config.go
const defaultConfigTemplate = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
##### main base config options #####
# TCP or UNIX socket address of the ABCI application,
# or the name of an ABCI application compiled in with the Tendermint binary
proxy_app = "{{ .BaseConfig.ProxyApp }}"
# A custom human readable name for this node
moniker = "{{ .BaseConfig.Moniker }}"
# If this node is many blocks behind the tip of the chain, FastSync
# allows them to catchup quickly by downloading blocks in parallel
# and verifying their commits
fast_sync = {{ .BaseConfig.FastSync }}
# Database backend: leveldb | memdb
db_backend = "{{ .BaseConfig.DBBackend }}"
# Database directory
db_path = "{{ .BaseConfig.DBPath }}"
# Output level for logging, including package level options
log_level = "{{ .BaseConfig.LogLevel }}"
##### additional base config options #####
# Path to the JSON file containing the initial validator set and other meta data
genesis_file = "{{ .BaseConfig.Genesis }}"
# Path to the JSON file containing the private key to use as a validator in the consensus protocol
priv_validator_file = "{{ .BaseConfig.PrivValidator }}"
# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
node_key_file = "{{ .BaseConfig.NodeKey}}"
# Mechanism to connect to the ABCI application: socket | grpc
abci = "{{ .BaseConfig.ABCI }}"
# TCP or UNIX socket address for the profiling server to listen on
prof_laddr = "{{ .BaseConfig.ProfListenAddress }}"
# If true, query the ABCI app on connecting to a new peer
# so the app can decide if we should keep the connection or not
filter_peers = {{ .BaseConfig.FilterPeers }}
##### advanced configuration options #####
##### rpc server configuration options #####
[rpc]
# TCP or UNIX socket address for the RPC server to listen on
laddr = "{{ .RPC.ListenAddress }}"
# TCP or UNIX socket address for the gRPC server to listen on
# NOTE: This server only supports /broadcast_tx_commit
grpc_laddr = "{{ .RPC.GRPCListenAddress }}"
# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
unsafe = {{ .RPC.Unsafe }}
##### peer to peer configuration options #####
[p2p]
# Address to listen for incoming connections
laddr = "{{ .P2P.ListenAddress }}"
# Comma separated list of seed nodes to connect to
seeds = "{{ .P2P.Seeds }}"
# Comma separated list of nodes to keep persistent connections to
# Do not add private peers to this list if you don't want them advertised
persistent_peers = "{{ .P2P.PersistentPeers }}"
# Path to address book
addr_book_file = "{{ .P2P.AddrBook }}"
# Set true for strict address routability rules
addr_book_strict = {{ .P2P.AddrBookStrict }}
# Time to wait before flushing messages out on the connection, in ms
flush_throttle_timeout = {{ .P2P.FlushThrottleTimeout }}
# Maximum number of peers to connect to
max_num_peers = {{ .P2P.MaxNumPeers }}
# Maximum size of a message packet payload, in bytes
max_packet_msg_payload_size = {{ .P2P.MaxPacketMsgPayloadSize }}
# Rate at which packets can be sent, in bytes/second
send_rate = {{ .P2P.SendRate }}
# Rate at which packets can be received, in bytes/second
recv_rate = {{ .P2P.RecvRate }}
# Set true to enable the peer-exchange reactor
pex = {{ .P2P.PexReactor }}
# Seed mode, in which node constantly crawls the network and looks for
# peers. If another node asks it for addresses, it responds and disconnects.
#
# Does not work if the peer-exchange reactor is disabled.
seed_mode = {{ .P2P.SeedMode }}
# Authenticated encryption
auth_enc = {{ .P2P.AuthEnc }}
# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
private_peer_ids = "{{ .P2P.PrivatePeerIDs }}"
##### mempool configuration options #####
[mempool]
recheck = {{ .Mempool.Recheck }}
recheck_empty = {{ .Mempool.RecheckEmpty }}
broadcast = {{ .Mempool.Broadcast }}
wal_dir = "{{ .Mempool.WalPath }}"
##### consensus configuration options #####
[consensus]
wal_file = "{{ .Consensus.WalPath }}"
wal_light = {{ .Consensus.WalLight }}
# All timeouts are in milliseconds
timeout_propose = {{ .Consensus.TimeoutPropose }}
timeout_propose_delta = {{ .Consensus.TimeoutProposeDelta }}
timeout_prevote = {{ .Consensus.TimeoutPrevote }}
timeout_prevote_delta = {{ .Consensus.TimeoutPrevoteDelta }}
timeout_precommit = {{ .Consensus.TimeoutPrecommit }}
timeout_precommit_delta = {{ .Consensus.TimeoutPrecommitDelta }}
timeout_commit = {{ .Consensus.TimeoutCommit }}
# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0)
skip_timeout_commit = {{ .Consensus.SkipTimeoutCommit }}
# BlockSize
max_block_size_txs = {{ .Consensus.MaxBlockSizeTxs }}
max_block_size_bytes = {{ .Consensus.MaxBlockSizeBytes }}
# EmptyBlocks mode and possible interval between empty blocks in seconds
create_empty_blocks = {{ .Consensus.CreateEmptyBlocks }}
create_empty_blocks_interval = {{ .Consensus.CreateEmptyBlocksInterval }}
# Reactor sleep duration parameters are in milliseconds
peer_gossip_sleep_duration = {{ .Consensus.PeerGossipSleepDuration }}
peer_query_maj23_sleep_duration = {{ .Consensus.PeerQueryMaj23SleepDuration }}
##### transactions indexer configuration options #####
[tx_index]
# What indexer to use for transactions
#
# Options:
# 1) "null" (default)
# 2) "kv" - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
indexer = "{{ .TxIndex.Indexer }}"
# Comma-separated list of tags to index (by default the only tag is tx hash)
#
# It's recommended to index only a subset of tags due to possible memory
# bloat. This is, of course, depends on the indexer's DB and the volume of
# transactions.
index_tags = "{{ .TxIndex.IndexTags }}"
# When set to true, tells indexer to index all tags. Note this may be not
# desirable (see the comment above). IndexTags has a precedence over
# IndexAllTags (i.e. when given both, IndexTags will be indexed).
index_all_tags = {{ .TxIndex.IndexAllTags }}
`
/****** these are for test settings ***********/
func ResetTestRoot(testName string) *Config {
rootDir := os.ExpandEnv("$HOME/.tendermint_test")
rootDir = filepath.Join(rootDir, testName)
// Remove ~/.tendermint_test_bak
if cmn.FileExists(rootDir + "_bak") {
if err := os.RemoveAll(rootDir + "_bak"); err != nil {
cmn.PanicSanity(err.Error())
}
}
// Move ~/.tendermint_test to ~/.tendermint_test_bak
if cmn.FileExists(rootDir) {
if err := os.Rename(rootDir, rootDir+"_bak"); err != nil {
cmn.PanicSanity(err.Error())
}
}
// Create new dir
if err := cmn.EnsureDir(rootDir, 0700); err != nil {
cmn.PanicSanity(err.Error())
}
if err := cmn.EnsureDir(filepath.Join(rootDir, defaultConfigDir), 0700); err != nil {
cmn.PanicSanity(err.Error())
}
if err := cmn.EnsureDir(filepath.Join(rootDir, defaultDataDir), 0700); err != nil {
cmn.PanicSanity(err.Error())
}
baseConfig := DefaultBaseConfig()
configFilePath := filepath.Join(rootDir, defaultConfigFilePath)
genesisFilePath := filepath.Join(rootDir, baseConfig.Genesis)
privFilePath := filepath.Join(rootDir, baseConfig.PrivValidator)
// Write default config file if missing.
if !cmn.FileExists(configFilePath) {
writeDefaultCondigFile(configFilePath)
}
if !cmn.FileExists(genesisFilePath) {
cmn.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644)
}
// we always overwrite the priv val
cmn.MustWriteFile(privFilePath, []byte(testPrivValidator), 0644)
config := TestConfig().SetRoot(rootDir)
return config
}
var testGenesis = `{
"genesis_time": "0001-01-01T00:00:00.000Z",
"chain_id": "tendermint_test",
"validators": [
{
"pub_key": {
"type": "AC26791624DE60",
"value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
},
"power": 10,
"name": ""
}
],
"app_hash": ""
}`
var testPrivValidator = `{
"address": "849CB2C877F87A20925F35D00AE6688342D25B47",
"pub_key": {
"type": "AC26791624DE60",
"value": "AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
},
"priv_key": {
"type": "954568A3288910",
"value": "EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ=="
},
"last_height": 0,
"last_round": 0,
"last_step": 0
}`

94
config/toml_test.go Normal file
View File

@ -0,0 +1,94 @@
package config
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func ensureFiles(t *testing.T, rootDir string, files ...string) {
for _, f := range files {
p := rootify(rootDir, f)
_, err := os.Stat(p)
assert.Nil(t, err, p)
}
}
func TestEnsureRoot(t *testing.T) {
require := require.New(t)
// setup temp dir for test
tmpDir, err := ioutil.TempDir("", "config-test")
require.Nil(err)
defer os.RemoveAll(tmpDir) // nolint: errcheck
// create root dir
EnsureRoot(tmpDir)
// make sure config is set properly
data, err := ioutil.ReadFile(filepath.Join(tmpDir, defaultConfigFilePath))
require.Nil(err)
if !checkConfig(string(data)) {
t.Fatalf("config file missing some information")
}
ensureFiles(t, tmpDir, "data")
}
func TestEnsureTestRoot(t *testing.T) {
require := require.New(t)
testName := "ensureTestRoot"
// create root dir
cfg := ResetTestRoot(testName)
rootDir := cfg.RootDir
// make sure config is set properly
data, err := ioutil.ReadFile(filepath.Join(rootDir, defaultConfigFilePath))
require.Nil(err)
if !checkConfig(string(data)) {
t.Fatalf("config file missing some information")
}
// TODO: make sure the cfg returned and testconfig are the same!
baseConfig := DefaultBaseConfig()
ensureFiles(t, rootDir, defaultDataDir, baseConfig.Genesis, baseConfig.PrivValidator)
}
func checkConfig(configFile string) bool {
var valid bool
// list of words we expect in the config
var elems = []string{
"moniker",
"seeds",
"proxy_app",
"fast_sync",
"create_empty_blocks",
"peer",
"timeout",
"broadcast",
"send",
"addr",
"wal",
"propose",
"max",
"genesis",
}
for _, e := range elems {
if !strings.Contains(configFile, e) {
valid = false
} else {
valid = true
}
}
return valid
}

View File

@ -1,21 +1,19 @@
package consensus
import (
"context"
"sync"
"testing"
"time"
"github.com/tendermint/tendermint/config/tendermint_test"
. "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
"github.com/tendermint/go-events"
"github.com/tendermint/go-p2p"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
func init() {
config = tendermint_test.ResetConfig("consensus_byzantine_test")
config = ResetConfig("consensus_byzantine_test")
}
//----------------------------------------------
@ -29,17 +27,62 @@ func init() {
// Heal partition and ensure A sees the commit
func TestByzantine(t *testing.T) {
N := 4
logger := consensusLogger()
css := randConsensusNet(N, "consensus_byzantine_test", newMockTickerFunc(false), newCounter)
// give the byzantine validator a normal ticker
css[0].SetTimeoutTicker(NewTimeoutTicker())
ticker := NewTimeoutTicker()
ticker.SetLogger(css[0].Logger)
css[0].SetTimeoutTicker(ticker)
switches := make([]*p2p.Switch, N)
p2pLogger := logger.With("module", "p2p")
for i := 0; i < N; i++ {
switches[i] = p2p.NewSwitch(cfg.NewMapConfig(nil))
switches[i] = p2p.NewSwitch(config.P2P)
switches[i].SetLogger(p2pLogger.With("validator", i))
}
eventChans := make([]chan interface{}, N)
reactors := make([]p2p.Reactor, N)
for i := 0; i < N; i++ {
// make first val byzantine
if i == 0 {
// NOTE: Now, test validators are MockPV, which by default doesn't
// do any safety checks.
css[i].privValidator.(*types.MockPV).DisableChecks()
css[i].decideProposal = func(j int) func(int64, int) {
return func(height int64, round int) {
byzantineDecideProposalFunc(t, height, round, css[j], switches[j])
}
}(i)
css[i].doPrevote = func(height int64, round int) {}
}
eventBus := types.NewEventBus()
eventBus.SetLogger(logger.With("module", "events", "validator", i))
err := eventBus.Start()
require.NoError(t, err)
defer eventBus.Stop()
eventChans[i] = make(chan interface{}, 1)
err = eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock, eventChans[i])
require.NoError(t, err)
conR := NewConsensusReactor(css[i], true) // so we dont start the consensus states
conR.SetLogger(logger.With("validator", i))
conR.SetEventBus(eventBus)
var conRI p2p.Reactor // nolint: gotype, gosimple
conRI = conR
// make first val byzantine
if i == 0 {
conRI = NewByzantineReactor(conR)
}
reactors[i] = conRI
}
defer func() {
for _, r := range reactors {
if rr, ok := r.(*ByzantineReactor); ok {
@ -49,38 +92,8 @@ func TestByzantine(t *testing.T) {
}
}
}()
eventChans := make([]chan interface{}, N)
for i := 0; i < N; i++ {
if i == 0 {
css[i].privValidator = NewByzantinePrivValidator(css[i].privValidator.(*types.PrivValidator))
// make byzantine
css[i].decideProposal = func(j int) func(int, int) {
return func(height, round int) {
byzantineDecideProposalFunc(height, round, css[j], switches[j])
}
}(i)
css[i].doPrevote = func(height, round int) {}
}
eventSwitch := events.NewEventSwitch()
_, err := eventSwitch.Start()
if err != nil {
t.Fatalf("Failed to start switch: %v", err)
}
eventChans[i] = subscribeToEvent(eventSwitch, "tester", types.EventStringNewBlock(), 1)
conR := NewConsensusReactor(css[i], true) // so we dont start the consensus states
conR.SetEventSwitch(eventSwitch)
var conRI p2p.Reactor
conRI = conR
if i == 0 {
conRI = NewByzantineReactor(conR)
}
reactors[i] = conRI
}
p2p.MakeConnectedSwitches(N, func(i int, s *p2p.Switch) *p2p.Switch {
p2p.MakeConnectedSwitches(config.P2P, N, func(i int, s *p2p.Switch) *p2p.Switch {
// ignore new switch s, we already made ours
switches[i].AddReactor("CONSENSUS", reactors[i])
return switches[i]
@ -95,32 +108,29 @@ func TestByzantine(t *testing.T) {
// start the state machines
byzR := reactors[0].(*ByzantineReactor)
s := byzR.reactor.conS.GetState()
byzR.reactor.SwitchToConsensus(s)
byzR.reactor.SwitchToConsensus(s, 0)
for i := 1; i < N; i++ {
cr := reactors[i].(*ConsensusReactor)
cr.SwitchToConsensus(cr.conS.GetState())
cr.SwitchToConsensus(cr.conS.GetState(), 0)
}
// byz proposer sends one block to peers[0]
// and the other block to peers[1] and peers[2].
// note peers and switches order don't match.
peers := switches[0].Peers().List()
// partition A
ind0 := getSwitchIndex(switches, peers[0])
// partition B
ind1 := getSwitchIndex(switches, peers[1])
ind2 := getSwitchIndex(switches, peers[2])
// connect the 2 peers in the larger partition
p2p.Connect2Switches(switches, ind1, ind2)
// wait for someone in the big partition to make a block
// wait for someone in the big partition (B) to make a block
<-eventChans[ind2]
select {
case <-eventChans[ind2]:
}
log.Notice("A block has been committed. Healing partition")
// connect the partitions
t.Log("A block has been committed. Healing partition")
p2p.Connect2Switches(switches, ind0, ind1)
p2p.Connect2Switches(switches, ind0, ind2)
@ -146,8 +156,8 @@ func TestByzantine(t *testing.T) {
case <-done:
case <-tick.C:
for i, reactor := range reactors {
t.Log(Fmt("Consensus Reactor %v", i))
t.Log(Fmt("%v", reactor))
t.Log(cmn.Fmt("Consensus Reactor %v", i))
t.Log(cmn.Fmt("%v", reactor))
}
t.Fatalf("Timed out waiting for all validators to commit first block")
}
@ -156,7 +166,7 @@ func TestByzantine(t *testing.T) {
//-------------------------------
// byzantine consensus functions
func byzantineDecideProposalFunc(height, round int, cs *ConsensusState, sw *p2p.Switch) {
func byzantineDecideProposalFunc(t *testing.T, height int64, round int, cs *ConsensusState, sw *p2p.Switch) {
// byzantine user should create two proposals and try to split the vote.
// Avoid sending on internalMsgQueue and running consensus state.
@ -164,20 +174,24 @@ func byzantineDecideProposalFunc(height, round int, cs *ConsensusState, sw *p2p.
block1, blockParts1 := cs.createProposalBlock()
polRound, polBlockID := cs.Votes.POLInfo()
proposal1 := types.NewProposal(height, round, blockParts1.Header(), polRound, polBlockID)
cs.privValidator.SignProposal(cs.state.ChainID, proposal1) // byzantine doesnt err
if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal1); err != nil {
t.Error(err)
}
// Create a new proposal block from state/txs from the mempool.
block2, blockParts2 := cs.createProposalBlock()
polRound, polBlockID = cs.Votes.POLInfo()
proposal2 := types.NewProposal(height, round, blockParts2.Header(), polRound, polBlockID)
cs.privValidator.SignProposal(cs.state.ChainID, proposal2) // byzantine doesnt err
if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal2); err != nil {
t.Error(err)
}
block1Hash := block1.Hash()
block2Hash := block2.Hash()
// broadcast conflicting proposals/block parts to peers
peers := sw.Peers().List()
log.Notice("Byzantine: broadcasting conflicting proposals", "peers", len(peers))
t.Logf("Byzantine: broadcasting conflicting proposals to %d peers", len(peers))
for i, peer := range peers {
if i < len(peers)/2 {
go sendProposalAndParts(height, round, cs, peer, proposal1, block1Hash, blockParts1)
@ -187,10 +201,10 @@ func byzantineDecideProposalFunc(height, round int, cs *ConsensusState, sw *p2p.
}
}
func sendProposalAndParts(height, round int, cs *ConsensusState, peer *p2p.Peer, proposal *types.Proposal, blockHash []byte, parts *types.PartSet) {
func sendProposalAndParts(height int64, round int, cs *ConsensusState, peer p2p.Peer, proposal *types.Proposal, blockHash []byte, parts *types.PartSet) {
// proposal
msg := &ProposalMessage{Proposal: proposal}
peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg))
// parts
for i := 0; i < parts.Total(); i++ {
@ -200,7 +214,7 @@ func sendProposalAndParts(height, round int, cs *ConsensusState, peer *p2p.Peer,
Round: round, // This tells peer that this part applies to us.
Part: part,
}
peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg))
}
// votes
@ -209,15 +223,15 @@ func sendProposalAndParts(height, round int, cs *ConsensusState, peer *p2p.Peer,
precommit, _ := cs.signVote(types.VoteTypePrecommit, blockHash, parts.Header())
cs.mtx.Unlock()
peer.Send(VoteChannel, struct{ ConsensusMessage }{&VoteMessage{prevote}})
peer.Send(VoteChannel, struct{ ConsensusMessage }{&VoteMessage{precommit}})
peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(&VoteMessage{prevote}))
peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(&VoteMessage{precommit}))
}
//----------------------------------------
// byzantine consensus reactor
type ByzantineReactor struct {
Service
cmn.Service
reactor *ConsensusReactor
}
@ -230,14 +244,14 @@ func NewByzantineReactor(conR *ConsensusReactor) *ByzantineReactor {
func (br *ByzantineReactor) SetSwitch(s *p2p.Switch) { br.reactor.SetSwitch(s) }
func (br *ByzantineReactor) GetChannels() []*p2p.ChannelDescriptor { return br.reactor.GetChannels() }
func (br *ByzantineReactor) AddPeer(peer *p2p.Peer) {
func (br *ByzantineReactor) AddPeer(peer p2p.Peer) {
if !br.reactor.IsRunning() {
return
}
// Create peerState for peer
peerState := NewPeerState(peer)
peer.Data.Set(types.PeerStateKey, peerState)
peerState := NewPeerState(peer).SetLogger(br.reactor.Logger)
peer.Set(types.PeerStateKey, peerState)
// Send our state to peer.
// If we're fast_syncing, broadcast a RoundStepMessage later upon SwitchToConsensus().
@ -245,53 +259,9 @@ func (br *ByzantineReactor) AddPeer(peer *p2p.Peer) {
br.reactor.sendNewRoundStepMessages(peer)
}
}
func (br *ByzantineReactor) RemovePeer(peer *p2p.Peer, reason interface{}) {
func (br *ByzantineReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
br.reactor.RemovePeer(peer, reason)
}
func (br *ByzantineReactor) Receive(chID byte, peer *p2p.Peer, msgBytes []byte) {
func (br *ByzantineReactor) Receive(chID byte, peer p2p.Peer, msgBytes []byte) {
br.reactor.Receive(chID, peer, msgBytes)
}
//----------------------------------------
// byzantine privValidator
type ByzantinePrivValidator struct {
Address []byte `json:"address"`
types.Signer `json:"-"`
mtx sync.Mutex
}
// Return a priv validator that will sign anything
func NewByzantinePrivValidator(pv *types.PrivValidator) *ByzantinePrivValidator {
return &ByzantinePrivValidator{
Address: pv.Address,
Signer: pv.Signer,
}
}
func (privVal *ByzantinePrivValidator) GetAddress() []byte {
return privVal.Address
}
func (privVal *ByzantinePrivValidator) SignVote(chainID string, vote *types.Vote) error {
privVal.mtx.Lock()
defer privVal.mtx.Unlock()
// Sign
vote.Signature = privVal.Sign(types.SignBytes(chainID, vote))
return nil
}
func (privVal *ByzantinePrivValidator) SignProposal(chainID string, proposal *types.Proposal) error {
privVal.mtx.Lock()
defer privVal.mtx.Unlock()
// Sign
proposal.Signature = privVal.Sign(types.SignBytes(chainID, proposal))
return nil
}
func (privVal *ByzantinePrivValidator) String() string {
return Fmt("PrivValidator{%X}", privVal.Address)
}

View File

@ -1,29 +0,0 @@
package consensus
import (
"github.com/tendermint/tendermint/types"
)
// XXX: WARNING: these functions can halt the consensus as firing events is synchronous.
// Make sure to read off the channels, and in the case of subscribeToEventRespond, to write back on it
// NOTE: if chanCap=0, this blocks on the event being consumed
func subscribeToEvent(evsw types.EventSwitch, receiver, eventID string, chanCap int) chan interface{} {
// listen for event
ch := make(chan interface{}, chanCap)
types.AddListenerForEvent(evsw, receiver, eventID, func(data types.TMEventData) {
ch <- data
})
return ch
}
// NOTE: this blocks on receiving a response after the event is consumed
func subscribeToEventRespond(evsw types.EventSwitch, receiver, eventID string) chan interface{} {
// listen for event
ch := make(chan interface{})
types.AddListenerForEvent(evsw, receiver, eventID, func(data types.TMEventData) {
ch <- data
<-ch
})
return ch
}

View File

@ -2,6 +2,7 @@ package consensus
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
@ -13,42 +14,55 @@ import (
abcicli "github.com/tendermint/abci/client"
abci "github.com/tendermint/abci/types"
. "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
dbm "github.com/tendermint/go-db"
"github.com/tendermint/go-p2p"
bc "github.com/tendermint/tendermint/blockchain"
"github.com/tendermint/tendermint/config/tendermint_test"
cfg "github.com/tendermint/tendermint/config"
cstypes "github.com/tendermint/tendermint/consensus/types"
mempl "github.com/tendermint/tendermint/mempool"
"github.com/tendermint/tendermint/p2p"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
"github.com/tendermint/abci/example/counter"
"github.com/tendermint/abci/example/dummy"
"github.com/tendermint/abci/example/kvstore"
"github.com/go-kit/kit/log/term"
)
var config cfg.Config // NOTE: must be reset for each _test.go file
var ensureTimeout = time.Duration(2)
const (
testSubscriber = "test-client"
)
// genesis, chain_id, priv_val
var config *cfg.Config // NOTE: must be reset for each _test.go file
var ensureTimeout = time.Second * 1 // must be in seconds because CreateEmptyBlocksInterval is
func ensureDir(dir string, mode os.FileMode) {
if err := EnsureDir(dir, mode); err != nil {
if err := cmn.EnsureDir(dir, mode); err != nil {
panic(err)
}
}
func ResetConfig(name string) *cfg.Config {
return cfg.ResetTestRoot(name)
}
//-------------------------------------------------------------------------------
// validator stub (a dummy consensus peer we control)
// validator stub (a kvstore consensus peer we control)
type validatorStub struct {
Index int // Validator index. NOTE: we don't assume validator set changes.
Height int
Height int64
Round int
*types.PrivValidator
types.PrivValidator
}
var testMinPower = 10
var testMinPower int64 = 10
func NewValidatorStub(privValidator *types.PrivValidator, valIndex int) *validatorStub {
func NewValidatorStub(privValidator types.PrivValidator, valIndex int) *validatorStub {
return &validatorStub{
Index: valIndex,
PrivValidator: privValidator,
@ -58,13 +72,14 @@ func NewValidatorStub(privValidator *types.PrivValidator, valIndex int) *validat
func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
vote := &types.Vote{
ValidatorIndex: vs.Index,
ValidatorAddress: vs.PrivValidator.Address,
ValidatorAddress: vs.PrivValidator.GetAddress(),
Height: vs.Height,
Round: vs.Round,
Timestamp: time.Now().UTC(),
Type: voteType,
BlockID: types.BlockID{hash, header},
}
err := vs.PrivValidator.SignVote(config.GetString("chain_id"), vote)
err := vs.PrivValidator.SignVote(config.ChainID(), vote)
return vote, err
}
@ -87,26 +102,26 @@ func signVotes(voteType byte, hash []byte, header types.PartSetHeader, vss ...*v
func incrementHeight(vss ...*validatorStub) {
for _, vs := range vss {
vs.Height += 1
vs.Height++
}
}
func incrementRound(vss ...*validatorStub) {
for _, vs := range vss {
vs.Round += 1
vs.Round++
}
}
//-------------------------------------------------------------------------------
// Functions for transitioning the consensus state
func startTestRound(cs *ConsensusState, height, round int) {
func startTestRound(cs *ConsensusState, height int64, round int) {
cs.enterNewRound(height, round)
cs.startRoutines(0)
}
// Create proposal block from cs1 but sign it with vs
func decideProposal(cs1 *ConsensusState, vs *validatorStub, height, round int) (proposal *types.Proposal, block *types.Block) {
func decideProposal(cs1 *ConsensusState, vs *validatorStub, height int64, round int) (proposal *types.Proposal, block *types.Block) {
block, blockParts := cs1.createProposalBlock()
if block == nil { // on error
panic("error creating proposal block")
@ -115,7 +130,7 @@ func decideProposal(cs1 *ConsensusState, vs *validatorStub, height, round int) (
// Make proposal
polRound, polBlockID := cs1.Votes.POLInfo()
proposal = types.NewProposal(height, round, blockParts.Header(), polRound, polBlockID)
if err := vs.SignProposal(config.GetString("chain_id"), proposal); err != nil {
if err := vs.SignProposal(cs1.state.ChainID, proposal); err != nil {
panic(err)
}
return
@ -135,7 +150,7 @@ func signAddVotes(to *ConsensusState, voteType byte, hash []byte, header types.P
func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *validatorStub, blockHash []byte) {
prevotes := cs.Votes.Prevotes(round)
var vote *types.Vote
if vote = prevotes.GetByAddress(privVal.Address); vote == nil {
if vote = prevotes.GetByAddress(privVal.GetAddress()); vote == nil {
panic("Failed to find prevote from validator")
}
if blockHash == nil {
@ -152,7 +167,7 @@ func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *valid
func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorStub, blockHash []byte) {
votes := cs.LastCommit
var vote *types.Vote
if vote = votes.GetByAddress(privVal.Address); vote == nil {
if vote = votes.GetByAddress(privVal.GetAddress()); vote == nil {
panic("Failed to find precommit from validator")
}
if !bytes.Equal(vote.BlockID.Hash, blockHash) {
@ -163,7 +178,7 @@ func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorS
func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
precommits := cs.Votes.Precommits(thisRound)
var vote *types.Vote
if vote = precommits.GetByAddress(privVal.Address); vote == nil {
if vote = precommits.GetByAddress(privVal.GetAddress()); vote == nil {
panic("Failed to find precommit from validator")
}
@ -200,11 +215,14 @@ func validatePrevoteAndPrecommit(t *testing.T, cs *ConsensusState, thisRound, lo
// genesis
func subscribeToVoter(cs *ConsensusState, addr []byte) chan interface{} {
voteCh0 := subscribeToEvent(cs.evsw, "tester", types.EventStringVote(), 1)
voteCh0 := make(chan interface{})
err := cs.eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryVote, voteCh0)
if err != nil {
panic(fmt.Sprintf("failed to subscribe %s to %v", testSubscriber, types.EventQueryVote))
}
voteCh := make(chan interface{})
go func() {
for {
v := <-voteCh0
for v := range voteCh0 {
vote := v.(types.EventDataVote)
// we only fire for our own votes
if bytes.Equal(addr, vote.Vote.ValidatorAddress) {
@ -215,27 +233,20 @@ func subscribeToVoter(cs *ConsensusState, addr []byte) chan interface{} {
return voteCh
}
func readVotes(ch chan interface{}, reads int) chan struct{} {
wg := make(chan struct{})
go func() {
for i := 0; i < reads; i++ {
<-ch // read the precommit event
}
close(wg)
}()
return wg
}
//-------------------------------------------------------------------------------
// consensus states
func newConsensusState(state *sm.State, pv *types.PrivValidator, app abci.Application) *ConsensusState {
func newConsensusState(state sm.State, pv types.PrivValidator, app abci.Application) *ConsensusState {
return newConsensusStateWithConfig(config, state, pv, app)
}
func newConsensusStateWithConfig(thisConfig cfg.Config, state *sm.State, pv *types.PrivValidator, app abci.Application) *ConsensusState {
// Get BlockStore
func newConsensusStateWithConfig(thisConfig *cfg.Config, state sm.State, pv types.PrivValidator, app abci.Application) *ConsensusState {
blockDB := dbm.NewMemDB()
return newConsensusStateWithConfigAndBlockStore(thisConfig, state, pv, app, blockDB)
}
func newConsensusStateWithConfigAndBlockStore(thisConfig *cfg.Config, state sm.State, pv types.PrivValidator, app abci.Application, blockDB dbm.DB) *ConsensusState {
// Get BlockStore
blockStore := bc.NewBlockStore(blockDB)
// one for mempool, one for consensus
@ -244,42 +255,37 @@ func newConsensusStateWithConfig(thisConfig cfg.Config, state *sm.State, pv *typ
proxyAppConnCon := abcicli.NewLocalClient(mtx, app)
// Make Mempool
mempool := mempl.NewMempool(thisConfig, proxyAppConnMem)
mempool := mempl.NewMempool(thisConfig.Mempool, proxyAppConnMem, 0)
mempool.SetLogger(log.TestingLogger().With("module", "mempool"))
if thisConfig.Consensus.WaitForTxs() {
mempool.EnableTxsAvailable()
}
// mock the evidence pool
evpool := types.MockEvidencePool{}
// Make ConsensusReactor
cs := NewConsensusState(thisConfig, state, proxyAppConnCon, blockStore, mempool)
stateDB := dbm.NewMemDB()
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
cs := NewConsensusState(thisConfig.Consensus, state, blockExec, blockStore, mempool, evpool)
cs.SetLogger(log.TestingLogger().With("module", "consensus"))
cs.SetPrivValidator(pv)
evsw := types.NewEventSwitch()
cs.SetEventSwitch(evsw)
evsw.Start()
eventBus := types.NewEventBus()
eventBus.SetLogger(log.TestingLogger().With("module", "events"))
eventBus.Start()
cs.SetEventBus(eventBus)
return cs
}
func loadPrivValidator(conf cfg.Config) *types.PrivValidator {
privValidatorFile := conf.GetString("priv_validator_file")
func loadPrivValidator(config *cfg.Config) *pvm.FilePV {
privValidatorFile := config.PrivValidatorFile()
ensureDir(path.Dir(privValidatorFile), 0700)
privValidator := types.LoadOrGenPrivValidator(privValidatorFile)
privValidator := pvm.LoadOrGenFilePV(privValidatorFile)
privValidator.Reset()
return privValidator
}
func fixedConsensusState() *ConsensusState {
stateDB := dbm.NewMemDB()
state := sm.MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
privValidator := loadPrivValidator(config)
cs := newConsensusState(state, privValidator, counter.NewCounterApplication(true))
return cs
}
func fixedConsensusStateDummy() *ConsensusState {
stateDB := dbm.NewMemDB()
state := sm.MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
privValidator := loadPrivValidator(config)
cs := newConsensusState(state, privValidator, dummy.NewDummyApplication())
return cs
}
func randConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
// Get State
state, privVals := randGenesisState(nValidators, false, 10)
@ -299,62 +305,97 @@ func randConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
//-------------------------------------------------------------------------------
func ensureNoNewStep(stepCh chan interface{}) {
timeout := time.NewTicker(ensureTimeout * time.Second)
func ensureNoNewStep(stepCh <-chan interface{}) {
timer := time.NewTimer(ensureTimeout)
select {
case <-timeout.C:
case <-timer.C:
break
case <-stepCh:
panic("We should be stuck waiting for more votes, not moving to the next step")
panic("We should be stuck waiting, not moving to the next step")
}
}
func ensureNewStep(stepCh <-chan interface{}) {
timer := time.NewTimer(ensureTimeout)
select {
case <-timer.C:
panic("We shouldnt be stuck waiting")
case <-stepCh:
break
}
}
//-------------------------------------------------------------------------------
// consensus nets
func randConsensusNet(nValidators int, testName string, tickerFunc func() TimeoutTicker, appFunc func() abci.Application) []*ConsensusState {
genDoc, privVals := randGenesisDoc(nValidators, false, 10)
// consensusLogger is a TestingLogger which uses a different
// color for each validator ("validator" key must exist).
func consensusLogger() log.Logger {
return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor {
for i := 0; i < len(keyvals)-1; i += 2 {
if keyvals[i] == "validator" {
return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))}
}
}
return term.FgBgColor{}
}).With("module", "consensus")
}
func randConsensusNet(nValidators int, testName string, tickerFunc func() TimeoutTicker, appFunc func() abci.Application, configOpts ...func(*cfg.Config)) []*ConsensusState {
genDoc, privVals := randGenesisDoc(nValidators, false, 30)
css := make([]*ConsensusState, nValidators)
logger := consensusLogger()
for i := 0; i < nValidators; i++ {
db := dbm.NewMemDB() // each state needs its own db
state := sm.MakeGenesisState(db, genDoc)
state.Save()
thisConfig := tendermint_test.ResetConfig(Fmt("%s_%d", testName, i))
ensureDir(path.Dir(thisConfig.GetString("cs_wal_file")), 0700) // dir for wal
css[i] = newConsensusStateWithConfig(thisConfig, state, privVals[i], appFunc())
stateDB := dbm.NewMemDB() // each state needs its own db
state, _ := sm.LoadStateFromDBOrGenesisDoc(stateDB, genDoc)
thisConfig := ResetConfig(cmn.Fmt("%s_%d", testName, i))
for _, opt := range configOpts {
opt(thisConfig)
}
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
app := appFunc()
vals := types.TM2PB.Validators(state.Validators)
app.InitChain(abci.RequestInitChain{Validators: vals})
css[i] = newConsensusStateWithConfig(thisConfig, state, privVals[i], app)
css[i].SetTimeoutTicker(tickerFunc())
css[i].SetLogger(logger.With("validator", i, "module", "consensus"))
}
return css
}
// nPeers = nValidators + nNotValidator
func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerFunc func() TimeoutTicker, appFunc func() abci.Application) []*ConsensusState {
genDoc, privVals := randGenesisDoc(nValidators, false, int64(testMinPower))
genDoc, privVals := randGenesisDoc(nValidators, false, testMinPower)
css := make([]*ConsensusState, nPeers)
logger := consensusLogger()
for i := 0; i < nPeers; i++ {
db := dbm.NewMemDB() // each state needs its own db
state := sm.MakeGenesisState(db, genDoc)
state.Save()
thisConfig := tendermint_test.ResetConfig(Fmt("%s_%d", testName, i))
ensureDir(path.Dir(thisConfig.GetString("cs_wal_file")), 0700) // dir for wal
var privVal *types.PrivValidator
stateDB := dbm.NewMemDB() // each state needs its own db
state, _ := sm.LoadStateFromDBOrGenesisDoc(stateDB, genDoc)
thisConfig := ResetConfig(cmn.Fmt("%s_%d", testName, i))
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
var privVal types.PrivValidator
if i < nValidators {
privVal = privVals[i]
} else {
privVal = types.GenPrivValidator()
_, tempFilePath := Tempfile("priv_validator_")
privVal.SetFile(tempFilePath)
_, tempFilePath := cmn.Tempfile("priv_validator_")
privVal = pvm.GenFilePV(tempFilePath)
}
css[i] = newConsensusStateWithConfig(thisConfig, state, privVal, appFunc())
app := appFunc()
vals := types.TM2PB.Validators(state.Validators)
app.InitChain(abci.RequestInitChain{Validators: vals})
css[i] = newConsensusStateWithConfig(thisConfig, state, privVal, app)
css[i].SetTimeoutTicker(tickerFunc())
css[i].SetLogger(logger.With("validator", i, "module", "consensus"))
}
return css
}
func getSwitchIndex(switches []*p2p.Switch, peer *p2p.Peer) int {
func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int {
for i, s := range switches {
if bytes.Equal(peer.NodeInfo.PubKey.Address(), s.NodeInfo().PubKey.Address()) {
if peer.NodeInfo().ID == s.NodeInfo().ID {
return i
}
}
@ -365,30 +406,31 @@ func getSwitchIndex(switches []*p2p.Switch, peer *p2p.Peer) int {
//-------------------------------------------------------------------------------
// genesis
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []*types.PrivValidator) {
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []types.PrivValidator) {
validators := make([]types.GenesisValidator, numValidators)
privValidators := make([]*types.PrivValidator, numValidators)
privValidators := make([]types.PrivValidator, numValidators)
for i := 0; i < numValidators; i++ {
val, privVal := types.RandValidator(randPower, minPower)
validators[i] = types.GenesisValidator{
PubKey: val.PubKey,
Amount: val.VotingPower,
Power: val.VotingPower,
}
privValidators[i] = privVal
}
sort.Sort(types.PrivValidatorsByAddress(privValidators))
return &types.GenesisDoc{
GenesisTime: time.Now(),
ChainID: config.GetString("chain_id"),
ChainID: config.ChainID(),
Validators: validators,
}, privValidators
}
func randGenesisState(numValidators int, randPower bool, minPower int64) (*sm.State, []*types.PrivValidator) {
func randGenesisState(numValidators int, randPower bool, minPower int64) (sm.State, []types.PrivValidator) {
genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower)
s0, _ := sm.MakeGenesisState(genDoc)
db := dbm.NewMemDB()
s0 := sm.MakeGenesisState(db, genDoc)
s0.Save()
sm.SaveState(db, s0)
return s0, privValidators
}
@ -414,12 +456,12 @@ type mockTicker struct {
fired bool
}
func (m *mockTicker) Start() (bool, error) {
return true, nil
func (m *mockTicker) Start() error {
return nil
}
func (m *mockTicker) Stop() bool {
return true
func (m *mockTicker) Stop() error {
return nil
}
func (m *mockTicker) ScheduleTimeout(ti timeoutInfo) {
@ -428,7 +470,7 @@ func (m *mockTicker) ScheduleTimeout(ti timeoutInfo) {
if m.onlyOnce && m.fired {
return
}
if ti.Step == RoundStepNewHeight {
if ti.Step == cstypes.RoundStepNewHeight {
m.c <- ti
m.fired = true
}
@ -438,13 +480,16 @@ func (m *mockTicker) Chan() <-chan timeoutInfo {
return m.c
}
func (mockTicker) SetLogger(log.Logger) {
}
//------------------------------------
func newCounter() abci.Application {
return counter.NewCounterApplication(true)
}
func newPersistentDummy() abci.Application {
dir, _ := ioutil.TempDir("/tmp", "persistent-dummy")
return dummy.NewPersistentDummyApplication(dir)
func newPersistentKVStore() abci.Application {
dir, _ := ioutil.TempDir("/tmp", "persistent-kvstore")
return kvstore.NewPersistentKVStoreApplication(dir)
}

View File

@ -1,18 +0,0 @@
package consensus
import (
"github.com/tendermint/go-logger"
)
var log = logger.New("module", "consensus")
/*
func init() {
log.SetHandler(
logger.LvlFilterHandler(
logger.LvlDebug,
logger.BypassHandler(),
),
)
}
*/

View File

@ -2,56 +2,121 @@ package consensus
import (
"encoding/binary"
"fmt"
"testing"
"time"
abci "github.com/tendermint/abci/types"
"github.com/tendermint/tendermint/config/tendermint_test"
"github.com/tendermint/tendermint/types"
"github.com/stretchr/testify/assert"
. "github.com/tendermint/go-common"
"github.com/tendermint/abci/example/code"
abci "github.com/tendermint/abci/types"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tendermint/types"
)
func init() {
config = tendermint_test.ResetConfig("consensus_mempool_test")
config = ResetConfig("consensus_mempool_test")
}
func TestTxConcurrentWithCommit(t *testing.T) {
func TestMempoolNoProgressUntilTxsAvailable(t *testing.T) {
config := ResetConfig("consensus_mempool_txs_available_test")
config.Consensus.CreateEmptyBlocks = false
state, privVals := randGenesisState(1, false, 10)
cs := newConsensusStateWithConfig(config, state, privVals[0], NewCounterApplication())
cs.mempool.EnableTxsAvailable()
height, round := cs.Height, cs.Round
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
startTestRound(cs, height, round)
ensureNewStep(newBlockCh) // first block gets committed
ensureNoNewStep(newBlockCh)
deliverTxsRange(cs, 0, 1)
ensureNewStep(newBlockCh) // commit txs
ensureNewStep(newBlockCh) // commit updated app hash
ensureNoNewStep(newBlockCh)
}
func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
config := ResetConfig("consensus_mempool_txs_available_test")
config.Consensus.CreateEmptyBlocksInterval = int(ensureTimeout.Seconds())
state, privVals := randGenesisState(1, false, 10)
cs := newConsensusStateWithConfig(config, state, privVals[0], NewCounterApplication())
cs.mempool.EnableTxsAvailable()
height, round := cs.Height, cs.Round
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
startTestRound(cs, height, round)
ensureNewStep(newBlockCh) // first block gets committed
ensureNoNewStep(newBlockCh) // then we dont make a block ...
ensureNewStep(newBlockCh) // until the CreateEmptyBlocksInterval has passed
}
func TestMempoolProgressInHigherRound(t *testing.T) {
config := ResetConfig("consensus_mempool_txs_available_test")
config.Consensus.CreateEmptyBlocks = false
state, privVals := randGenesisState(1, false, 10)
cs := newConsensusStateWithConfig(config, state, privVals[0], NewCounterApplication())
cs.mempool.EnableTxsAvailable()
height, round := cs.Height, cs.Round
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
newRoundCh := subscribe(cs.eventBus, types.EventQueryNewRound)
timeoutCh := subscribe(cs.eventBus, types.EventQueryTimeoutPropose)
cs.setProposal = func(proposal *types.Proposal) error {
if cs.Height == 2 && cs.Round == 0 {
// dont set the proposal in round 0 so we timeout and
// go to next round
cs.Logger.Info("Ignoring set proposal at height 2, round 0")
return nil
}
return cs.defaultSetProposal(proposal)
}
startTestRound(cs, height, round)
ensureNewStep(newRoundCh) // first round at first height
ensureNewStep(newBlockCh) // first block gets committed
ensureNewStep(newRoundCh) // first round at next height
deliverTxsRange(cs, 0, 1) // we deliver txs, but dont set a proposal so we get the next round
<-timeoutCh
ensureNewStep(newRoundCh) // wait for the next round
ensureNewStep(newBlockCh) // now we can commit the block
}
func deliverTxsRange(cs *ConsensusState, start, end int) {
// Deliver some txs.
for i := start; i < end; i++ {
txBytes := make([]byte, 8)
binary.BigEndian.PutUint64(txBytes, uint64(i))
err := cs.mempool.CheckTx(txBytes, nil)
if err != nil {
panic(cmn.Fmt("Error after CheckTx: %v", err))
}
}
}
func TestMempoolTxConcurrentWithCommit(t *testing.T) {
state, privVals := randGenesisState(1, false, 10)
cs := newConsensusState(state, privVals[0], NewCounterApplication())
height, round := cs.Height, cs.Round
newBlockCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewBlock(), 1)
deliverTxsRange := func(start, end int) {
// Deliver some txs.
for i := start; i < end; i++ {
txBytes := make([]byte, 8)
binary.BigEndian.PutUint64(txBytes, uint64(i))
err := cs.mempool.CheckTx(txBytes, nil)
if err != nil {
panic(Fmt("Error after CheckTx: %v", err))
}
// time.Sleep(time.Microsecond * time.Duration(rand.Int63n(3000)))
}
}
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
NTxs := 10000
go deliverTxsRange(0, NTxs)
go deliverTxsRange(cs, 0, NTxs)
startTestRound(cs, height, round)
ticker := time.NewTicker(time.Second * 20)
for nTxs := 0; nTxs < NTxs; {
ticker := time.NewTicker(time.Second * 30)
select {
case b := <-newBlockCh:
nTxs += b.(types.EventDataNewBlock).Block.Header.NumTxs
evt := b.(types.EventDataNewBlock)
nTxs += int(evt.Block.Header.NumTxs)
case <-ticker.C:
panic("Timed out waiting to commit blocks with transactions")
}
}
}
func TestRmBadTx(t *testing.T) {
func TestMempoolRmBadTx(t *testing.T) {
state, privVals := randGenesisState(1, false, 10)
app := NewCounterApplication()
cs := newConsensusState(state, privVals[0], app)
@ -59,41 +124,44 @@ func TestRmBadTx(t *testing.T) {
// increment the counter by 1
txBytes := make([]byte, 8)
binary.BigEndian.PutUint64(txBytes, uint64(0))
app.DeliverTx(txBytes)
app.Commit()
ch := make(chan struct{})
cbCh := make(chan struct{})
resDeliver := app.DeliverTx(txBytes)
assert.False(t, resDeliver.IsErr(), cmn.Fmt("expected no error. got %v", resDeliver))
resCommit := app.Commit()
assert.True(t, len(resCommit.Data) > 0)
emptyMempoolCh := make(chan struct{})
checkTxRespCh := make(chan struct{})
go func() {
// Try to send the tx through the mempool.
// CheckTx should not err, but the app should return a bad abci code
// and the tx should get removed from the pool
err := cs.mempool.CheckTx(txBytes, func(r *abci.Response) {
if r.GetCheckTx().Code != abci.CodeType_BadNonce {
if r.GetCheckTx().Code != code.CodeTypeBadNonce {
t.Fatalf("expected checktx to return bad nonce, got %v", r)
}
cbCh <- struct{}{}
checkTxRespCh <- struct{}{}
})
if err != nil {
t.Fatal("Error after CheckTx: %v", err)
t.Fatalf("Error after CheckTx: %v", err)
}
// check for the tx
for {
time.Sleep(time.Second)
txs := cs.mempool.Reap(1)
if len(txs) == 0 {
ch <- struct{}{}
emptyMempoolCh <- struct{}{}
return
}
time.Sleep(10 * time.Millisecond)
}
}()
// Wait until the tx returns
ticker := time.After(time.Second * 5)
select {
case <-cbCh:
case <-checkTxRespCh:
// success
case <-ticker:
t.Fatalf("Timed out waiting for tx to return")
@ -102,7 +170,7 @@ func TestRmBadTx(t *testing.T) {
// Wait until the tx is removed
ticker = time.After(time.Second * 5)
select {
case <-ch:
case <-emptyMempoolCh:
// success
case <-ticker:
t.Fatalf("Timed out waiting for tx to be removed")
@ -121,37 +189,44 @@ func NewCounterApplication() *CounterApplication {
return &CounterApplication{}
}
func (app *CounterApplication) Info() abci.ResponseInfo {
return abci.ResponseInfo{Data: Fmt("txs:%v", app.txCount)}
func (app *CounterApplication) Info(req abci.RequestInfo) abci.ResponseInfo {
return abci.ResponseInfo{Data: cmn.Fmt("txs:%v", app.txCount)}
}
func (app *CounterApplication) DeliverTx(tx []byte) abci.Result {
return runTx(tx, &app.txCount)
func (app *CounterApplication) DeliverTx(tx []byte) abci.ResponseDeliverTx {
txValue := txAsUint64(tx)
if txValue != uint64(app.txCount) {
return abci.ResponseDeliverTx{
Code: code.CodeTypeBadNonce,
Log: fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.txCount, txValue)}
}
app.txCount++
return abci.ResponseDeliverTx{Code: code.CodeTypeOK}
}
func (app *CounterApplication) CheckTx(tx []byte) abci.Result {
return runTx(tx, &app.mempoolTxCount)
func (app *CounterApplication) CheckTx(tx []byte) abci.ResponseCheckTx {
txValue := txAsUint64(tx)
if txValue != uint64(app.mempoolTxCount) {
return abci.ResponseCheckTx{
Code: code.CodeTypeBadNonce,
Log: fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.mempoolTxCount, txValue)}
}
app.mempoolTxCount++
return abci.ResponseCheckTx{Code: code.CodeTypeOK}
}
func runTx(tx []byte, countPtr *int) abci.Result {
count := *countPtr
func txAsUint64(tx []byte) uint64 {
tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8)
if txValue != uint64(count) {
return abci.ErrBadNonce.AppendLog(Fmt("Invalid nonce. Expected %v, got %v", count, txValue))
}
*countPtr += 1
return abci.OK
return binary.BigEndian.Uint64(tx8)
}
func (app *CounterApplication) Commit() abci.Result {
func (app *CounterApplication) Commit() abci.ResponseCommit {
app.mempoolTxCount = app.txCount
if app.txCount == 0 {
return abci.OK
} else {
hash := make([]byte, 8)
binary.BigEndian.PutUint64(hash, uint64(app.txCount))
return abci.NewResultOK(hash, "")
return abci.ResponseCommit{}
}
hash := make([]byte, 8)
binary.BigEndian.PutUint64(hash, uint64(app.txCount))
return abci.ResponseCommit{Data: hash}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,88 +1,243 @@
package consensus
import (
"context"
"fmt"
"os"
"runtime"
"runtime/pprof"
"sync"
"testing"
"time"
"github.com/tendermint/tendermint/config/tendermint_test"
"github.com/tendermint/abci/example/kvstore"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
"github.com/tendermint/go-events"
"github.com/tendermint/go-p2p"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
p2pdummy "github.com/tendermint/tendermint/p2p/dummy"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/abci/example/dummy"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func init() {
config = tendermint_test.ResetConfig("consensus_reactor_test")
config = ResetConfig("consensus_reactor_test")
}
//----------------------------------------------
// in-process testnets
func startConsensusNet(t *testing.T, css []*ConsensusState, N int, subscribeEventRespond bool) ([]*ConsensusReactor, []chan interface{}) {
func startConsensusNet(t *testing.T, css []*ConsensusState, N int) ([]*ConsensusReactor, []chan interface{}, []*types.EventBus) {
reactors := make([]*ConsensusReactor, N)
eventChans := make([]chan interface{}, N)
eventBuses := make([]*types.EventBus, N)
for i := 0; i < N; i++ {
/*logger, err := tmflags.ParseLogLevel("consensus:info,*:error", logger, "info")
if err != nil { t.Fatal(err)}*/
reactors[i] = NewConsensusReactor(css[i], true) // so we dont start the consensus states
reactors[i].SetLogger(css[i].Logger)
eventSwitch := events.NewEventSwitch()
_, err := eventSwitch.Start()
if err != nil {
t.Fatalf("Failed to start switch: %v", err)
}
// eventBus is already started with the cs
eventBuses[i] = css[i].eventBus
reactors[i].SetEventBus(eventBuses[i])
reactors[i].SetEventSwitch(eventSwitch)
if subscribeEventRespond {
eventChans[i] = subscribeToEventRespond(eventSwitch, "tester", types.EventStringNewBlock())
} else {
eventChans[i] = subscribeToEvent(eventSwitch, "tester", types.EventStringNewBlock(), 1)
}
eventChans[i] = make(chan interface{}, 1)
err := eventBuses[i].Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock, eventChans[i])
require.NoError(t, err)
}
// make connected switches and start all reactors
p2p.MakeConnectedSwitches(N, func(i int, s *p2p.Switch) *p2p.Switch {
p2p.MakeConnectedSwitches(config.P2P, N, func(i int, s *p2p.Switch) *p2p.Switch {
s.AddReactor("CONSENSUS", reactors[i])
s.SetLogger(reactors[i].conS.Logger.With("module", "p2p"))
return s
}, p2p.Connect2Switches)
// now that everyone is connected, start the state machines
// If we started the state machines before everyone was connected,
// we'd block when the cs fires NewBlockEvent and the peers are trying to start their reactors
// TODO: is this still true with new pubsub?
for i := 0; i < N; i++ {
s := reactors[i].conS.GetState()
reactors[i].SwitchToConsensus(s)
reactors[i].SwitchToConsensus(s, 0)
}
return reactors, eventChans
return reactors, eventChans, eventBuses
}
func stopConsensusNet(reactors []*ConsensusReactor) {
for _, r := range reactors {
func stopConsensusNet(logger log.Logger, reactors []*ConsensusReactor, eventBuses []*types.EventBus) {
logger.Info("stopConsensusNet", "n", len(reactors))
for i, r := range reactors {
logger.Info("stopConsensusNet: Stopping ConsensusReactor", "i", i)
r.Switch.Stop()
}
for i, b := range eventBuses {
logger.Info("stopConsensusNet: Stopping eventBus", "i", i)
b.Stop()
}
logger.Info("stopConsensusNet: DONE", "n", len(reactors))
}
// Ensure a testnet makes blocks
func TestReactor(t *testing.T) {
func TestReactorBasic(t *testing.T) {
N := 4
css := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter)
reactors, eventChans := startConsensusNet(t, css, N, false)
defer stopConsensusNet(reactors)
reactors, eventChans, eventBuses := startConsensusNet(t, css, N)
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
// wait till everyone makes the first new block
timeoutWaitGroup(t, N, func(wg *sync.WaitGroup, j int) {
timeoutWaitGroup(t, N, func(j int) {
<-eventChans[j]
wg.Done()
}, css)
}
// Ensure a testnet sends proposal heartbeats and makes blocks when there are txs
func TestReactorProposalHeartbeats(t *testing.T) {
N := 4
css := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter,
func(c *cfg.Config) {
c.Consensus.CreateEmptyBlocks = false
})
reactors, eventChans, eventBuses := startConsensusNet(t, css, N)
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
heartbeatChans := make([]chan interface{}, N)
var err error
for i := 0; i < N; i++ {
heartbeatChans[i] = make(chan interface{}, 1)
err = eventBuses[i].Subscribe(context.Background(), testSubscriber, types.EventQueryProposalHeartbeat, heartbeatChans[i])
require.NoError(t, err)
}
// wait till everyone sends a proposal heartbeat
timeoutWaitGroup(t, N, func(j int) {
<-heartbeatChans[j]
}, css)
// send a tx
if err := css[3].mempool.CheckTx([]byte{1, 2, 3}, nil); err != nil {
//t.Fatal(err)
}
// wait till everyone makes the first new block
timeoutWaitGroup(t, N, func(j int) {
<-eventChans[j]
}, css)
}
// Test we record block parts from other peers
func TestReactorRecordsBlockParts(t *testing.T) {
// create dummy peer
peer := p2pdummy.NewPeer()
ps := NewPeerState(peer).SetLogger(log.TestingLogger())
peer.Set(types.PeerStateKey, ps)
// create reactor
css := randConsensusNet(1, "consensus_reactor_records_block_parts_test", newMockTickerFunc(true), newPersistentKVStore)
reactor := NewConsensusReactor(css[0], false) // so we dont start the consensus states
reactor.SetEventBus(css[0].eventBus)
reactor.SetLogger(log.TestingLogger())
sw := p2p.MakeSwitch(cfg.DefaultP2PConfig(), 1, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw })
reactor.SetSwitch(sw)
err := reactor.Start()
require.NoError(t, err)
defer reactor.Stop()
// 1) new block part
parts := types.NewPartSetFromData(cmn.RandBytes(100), 10)
msg := &BlockPartMessage{
Height: 2,
Round: 0,
Part: parts.GetPart(0),
}
bz, err := cdc.MarshalBinaryBare(msg)
require.NoError(t, err)
reactor.Receive(DataChannel, peer, bz)
require.Equal(t, 1, ps.BlockPartsSent(), "number of block parts sent should have increased by 1")
// 2) block part with the same height, but different round
msg.Round = 1
bz, err = cdc.MarshalBinaryBare(msg)
require.NoError(t, err)
reactor.Receive(DataChannel, peer, bz)
require.Equal(t, 1, ps.BlockPartsSent(), "number of block parts sent should stay the same")
// 3) block part from earlier height
msg.Height = 1
msg.Round = 0
bz, err = cdc.MarshalBinaryBare(msg)
require.NoError(t, err)
reactor.Receive(DataChannel, peer, bz)
require.Equal(t, 1, ps.BlockPartsSent(), "number of block parts sent should stay the same")
}
// Test we record votes from other peers
func TestReactorRecordsVotes(t *testing.T) {
// create dummy peer
peer := p2pdummy.NewPeer()
ps := NewPeerState(peer).SetLogger(log.TestingLogger())
peer.Set(types.PeerStateKey, ps)
// create reactor
css := randConsensusNet(1, "consensus_reactor_records_votes_test", newMockTickerFunc(true), newPersistentKVStore)
reactor := NewConsensusReactor(css[0], false) // so we dont start the consensus states
reactor.SetEventBus(css[0].eventBus)
reactor.SetLogger(log.TestingLogger())
sw := p2p.MakeSwitch(cfg.DefaultP2PConfig(), 1, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw })
reactor.SetSwitch(sw)
err := reactor.Start()
require.NoError(t, err)
defer reactor.Stop()
_, val := css[0].state.Validators.GetByIndex(0)
// 1) new vote
vote := &types.Vote{
ValidatorIndex: 0,
ValidatorAddress: val.Address,
Height: 2,
Round: 0,
Timestamp: time.Now().UTC(),
Type: types.VoteTypePrevote,
BlockID: types.BlockID{},
}
bz, err := cdc.MarshalBinaryBare(&VoteMessage{vote})
require.NoError(t, err)
reactor.Receive(VoteChannel, peer, bz)
assert.Equal(t, 1, ps.VotesSent(), "number of votes sent should have increased by 1")
// 2) vote with the same height, but different round
vote.Round = 1
bz, err = cdc.MarshalBinaryBare(&VoteMessage{vote})
require.NoError(t, err)
reactor.Receive(VoteChannel, peer, bz)
assert.Equal(t, 1, ps.VotesSent(), "number of votes sent should stay the same")
// 3) vote from earlier height
vote.Height = 1
vote.Round = 0
bz, err = cdc.MarshalBinaryBare(&VoteMessage{vote})
require.NoError(t, err)
reactor.Receive(VoteChannel, peer, bz)
assert.Equal(t, 1, ps.VotesSent(), "number of votes sent should stay the same")
}
//-------------------------------------------------------------
// ensure we can make blocks despite cycling a validator set
func TestVotingPowerChange(t *testing.T) {
func TestReactorVotingPowerChange(t *testing.T) {
nVals := 4
css := randConsensusNet(nVals, "consensus_voting_power_changes_test", newMockTickerFunc(true), newPersistentDummy)
reactors, eventChans := startConsensusNet(t, css, nVals, true)
defer stopConsensusNet(reactors)
logger := log.TestingLogger()
css := randConsensusNet(nVals, "consensus_voting_power_changes_test", newMockTickerFunc(true), newPersistentKVStore)
reactors, eventChans, eventBuses := startConsensusNet(t, css, nVals)
defer stopConsensusNet(logger, reactors, eventBuses)
// map of active validators
activeVals := make(map[string]struct{})
@ -91,21 +246,19 @@ func TestVotingPowerChange(t *testing.T) {
}
// wait till everyone makes block 1
timeoutWaitGroup(t, nVals, func(wg *sync.WaitGroup, j int) {
timeoutWaitGroup(t, nVals, func(j int) {
<-eventChans[j]
eventChans[j] <- struct{}{}
wg.Done()
}, css)
//---------------------------------------------------------------------------
log.Info("---------------------------- Testing changing the voting power of one validator a few times")
logger.Debug("---------------------------- Testing changing the voting power of one validator a few times")
val1PubKey := css[0].privValidator.(*types.PrivValidator).PubKey
updateValidatorTx := dummy.MakeValSetChangeTx(val1PubKey.Bytes(), 25)
val1PubKey := css[0].privValidator.GetPubKey()
updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKey.Bytes(), 25)
previousTotalVotingPower := css[0].GetRoundState().LastValidators.TotalVotingPower()
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css)
waitForAndValidateBlockWithTx(t, nVals, activeVals, eventChans, css, updateValidatorTx)
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css)
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css)
@ -113,11 +266,11 @@ func TestVotingPowerChange(t *testing.T) {
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
}
updateValidatorTx = dummy.MakeValSetChangeTx(val1PubKey.Bytes(), 2)
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKey.Bytes(), 2)
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css)
waitForAndValidateBlockWithTx(t, nVals, activeVals, eventChans, css, updateValidatorTx)
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css)
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css)
@ -125,11 +278,11 @@ func TestVotingPowerChange(t *testing.T) {
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
}
updateValidatorTx = dummy.MakeValSetChangeTx(val1PubKey.Bytes(), 100)
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKey.Bytes(), 26)
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css)
waitForAndValidateBlockWithTx(t, nVals, activeVals, eventChans, css, updateValidatorTx)
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css)
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css)
@ -138,12 +291,15 @@ func TestVotingPowerChange(t *testing.T) {
}
}
func TestValidatorSetChanges(t *testing.T) {
func TestReactorValidatorSetChanges(t *testing.T) {
nPeers := 7
nVals := 4
css := randConsensusNetWithPeers(nVals, nPeers, "consensus_val_set_changes_test", newMockTickerFunc(true), newPersistentDummy)
reactors, eventChans := startConsensusNet(t, css, nPeers, true)
defer stopConsensusNet(reactors)
css := randConsensusNetWithPeers(nVals, nPeers, "consensus_val_set_changes_test", newMockTickerFunc(true), newPersistentKVStore)
logger := log.TestingLogger()
reactors, eventChans, eventBuses := startConsensusNet(t, css, nPeers)
defer stopConsensusNet(logger, reactors, eventBuses)
// map of active validators
activeVals := make(map[string]struct{})
@ -152,17 +308,15 @@ func TestValidatorSetChanges(t *testing.T) {
}
// wait till everyone makes block 1
timeoutWaitGroup(t, nPeers, func(wg *sync.WaitGroup, j int) {
timeoutWaitGroup(t, nPeers, func(j int) {
<-eventChans[j]
eventChans[j] <- struct{}{}
wg.Done()
}, css)
//---------------------------------------------------------------------------
log.Info("---------------------------- Testing adding one validator")
logger.Info("---------------------------- Testing adding one validator")
newValidatorPubKey1 := css[nVals].privValidator.(*types.PrivValidator).PubKey
newValidatorTx1 := dummy.MakeValSetChangeTx(newValidatorPubKey1.Bytes(), uint64(testMinPower))
newValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
newValidatorTx1 := kvstore.MakeValSetChangeTx(newValidatorPubKey1.Bytes(), testMinPower)
// wait till everyone makes block 2
// ensure the commit includes all validators
@ -171,7 +325,7 @@ func TestValidatorSetChanges(t *testing.T) {
// wait till everyone makes block 3.
// it includes the commit for block 2, which is by the original validator set
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, newValidatorTx1)
// wait till everyone makes block 4.
// it includes the commit for block 3, which is by the original validator set
@ -182,52 +336,52 @@ func TestValidatorSetChanges(t *testing.T) {
// wait till everyone makes block 5
// it includes the commit for block 4, which should have the updated validator set
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, eventChans, css)
//---------------------------------------------------------------------------
log.Info("---------------------------- Testing changing the voting power of one validator")
logger.Info("---------------------------- Testing changing the voting power of one validator")
updateValidatorPubKey1 := css[nVals].privValidator.(*types.PrivValidator).PubKey
updateValidatorTx1 := dummy.MakeValSetChangeTx(updateValidatorPubKey1.Bytes(), 25)
updateValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updateValidatorPubKey1.Bytes(), 25)
previousTotalVotingPower := css[nVals].GetRoundState().LastValidators.TotalVotingPower()
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, updateValidatorTx1)
waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, updateValidatorTx1)
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, eventChans, css)
if css[nVals].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower {
t.Errorf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[nVals].GetRoundState().LastValidators.TotalVotingPower())
}
//---------------------------------------------------------------------------
log.Info("---------------------------- Testing adding two validators at once")
logger.Info("---------------------------- Testing adding two validators at once")
newValidatorPubKey2 := css[nVals+1].privValidator.(*types.PrivValidator).PubKey
newValidatorTx2 := dummy.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), uint64(testMinPower))
newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey()
newValidatorTx2 := kvstore.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), testMinPower)
newValidatorPubKey3 := css[nVals+2].privValidator.(*types.PrivValidator).PubKey
newValidatorTx3 := dummy.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), uint64(testMinPower))
newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey()
newValidatorTx3 := kvstore.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), testMinPower)
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3)
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3)
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
activeVals[string(newValidatorPubKey2.Address())] = struct{}{}
activeVals[string(newValidatorPubKey3.Address())] = struct{}{}
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, eventChans, css)
//---------------------------------------------------------------------------
log.Info("---------------------------- Testing removing two validators at once")
logger.Info("---------------------------- Testing removing two validators at once")
removeValidatorTx2 := dummy.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), 0)
removeValidatorTx3 := dummy.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), 0)
removeValidatorTx2 := kvstore.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), 0)
removeValidatorTx3 := kvstore.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), 0)
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, removeValidatorTx2, removeValidatorTx3)
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, removeValidatorTx2, removeValidatorTx3)
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
delete(activeVals, string(newValidatorPubKey2.Address()))
delete(activeVals, string(newValidatorPubKey3.Address()))
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, eventChans, css)
}
// Check we can make blocks with skip_timeout_commit=false
@ -236,35 +390,89 @@ func TestReactorWithTimeoutCommit(t *testing.T) {
css := randConsensusNet(N, "consensus_reactor_with_timeout_commit_test", newMockTickerFunc(false), newCounter)
// override default SkipTimeoutCommit == true for tests
for i := 0; i < N; i++ {
css[i].timeoutParams.SkipTimeoutCommit = false
css[i].config.SkipTimeoutCommit = false
}
reactors, eventChans := startConsensusNet(t, css, N-1, false)
defer stopConsensusNet(reactors)
reactors, eventChans, eventBuses := startConsensusNet(t, css, N-1)
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
// wait till everyone makes the first new block
timeoutWaitGroup(t, N-1, func(wg *sync.WaitGroup, j int) {
timeoutWaitGroup(t, N-1, func(j int) {
<-eventChans[j]
wg.Done()
}, css)
}
func waitForAndValidateBlock(t *testing.T, n int, activeVals map[string]struct{}, eventChans []chan interface{}, css []*ConsensusState, txs ...[]byte) {
timeoutWaitGroup(t, n, func(wg *sync.WaitGroup, j int) {
newBlockI := <-eventChans[j]
newBlock := newBlockI.(types.EventDataNewBlock).Block
log.Warn("Got block", "height", newBlock.Height, "validator", j)
err := validateBlock(newBlock, activeVals)
if err != nil {
t.Fatal(err)
timeoutWaitGroup(t, n, func(j int) {
css[j].Logger.Debug("waitForAndValidateBlock")
newBlockI, ok := <-eventChans[j]
if !ok {
return
}
newBlock := newBlockI.(types.EventDataNewBlock).Block
css[j].Logger.Debug("waitForAndValidateBlock: Got block", "height", newBlock.Height)
err := validateBlock(newBlock, activeVals)
assert.Nil(t, err)
for _, tx := range txs {
css[j].mempool.CheckTx(tx, nil)
assert.Nil(t, err)
}
}, css)
}
func waitForAndValidateBlockWithTx(t *testing.T, n int, activeVals map[string]struct{}, eventChans []chan interface{}, css []*ConsensusState, txs ...[]byte) {
timeoutWaitGroup(t, n, func(j int) {
ntxs := 0
BLOCK_TX_LOOP:
for {
css[j].Logger.Debug("waitForAndValidateBlockWithTx", "ntxs", ntxs)
newBlockI, ok := <-eventChans[j]
if !ok {
return
}
newBlock := newBlockI.(types.EventDataNewBlock).Block
css[j].Logger.Debug("waitForAndValidateBlockWithTx: Got block", "height", newBlock.Height)
err := validateBlock(newBlock, activeVals)
assert.Nil(t, err)
// check that txs match the txs we're waiting for.
// note they could be spread over multiple blocks,
// but they should be in order.
for _, tx := range newBlock.Data.Txs {
assert.EqualValues(t, txs[ntxs], tx)
ntxs++
}
if ntxs == len(txs) {
break BLOCK_TX_LOOP
}
}
eventChans[j] <- struct{}{}
wg.Done()
log.Warn("Done wait group", "height", newBlock.Height, "validator", j)
}, css)
}
func waitForBlockWithUpdatedValsAndValidateIt(t *testing.T, n int, updatedVals map[string]struct{}, eventChans []chan interface{}, css []*ConsensusState) {
timeoutWaitGroup(t, n, func(j int) {
var newBlock *types.Block
LOOP:
for {
css[j].Logger.Debug("waitForBlockWithUpdatedValsAndValidateIt")
newBlockI, ok := <-eventChans[j]
if !ok {
return
}
newBlock = newBlockI.(types.EventDataNewBlock).Block
if newBlock.LastCommit.Size() == len(updatedVals) {
css[j].Logger.Debug("waitForBlockWithUpdatedValsAndValidateIt: Got block", "height", newBlock.Height)
break LOOP
} else {
css[j].Logger.Debug("waitForBlockWithUpdatedValsAndValidateIt: Got block with no new validators. Skipping", "height", newBlock.Height)
}
}
err := validateBlock(newBlock, updatedVals)
assert.Nil(t, err)
}, css)
}
@ -282,11 +490,14 @@ func validateBlock(block *types.Block, activeVals map[string]struct{}) error {
return nil
}
func timeoutWaitGroup(t *testing.T, n int, f func(*sync.WaitGroup, int), css []*ConsensusState) {
func timeoutWaitGroup(t *testing.T, n int, f func(int), css []*ConsensusState) {
wg := new(sync.WaitGroup)
wg.Add(n)
for i := 0; i < n; i++ {
go f(wg, i)
go func(j int) {
f(j)
wg.Done()
}(i)
}
done := make(chan struct{})
@ -295,15 +506,28 @@ func timeoutWaitGroup(t *testing.T, n int, f func(*sync.WaitGroup, int), css []*
close(done)
}()
// we're running many nodes in-process, possibly in in a virtual machine,
// and spewing debug messages - making a block could take a while,
timeout := time.Second * 300
select {
case <-done:
case <-time.After(time.Second * 10):
case <-time.After(timeout):
for i, cs := range css {
fmt.Println("#################")
fmt.Println("Validator", i)
fmt.Println(cs.GetRoundState())
fmt.Println("")
t.Log("#################")
t.Log("Validator", i)
t.Log(cs.GetRoundState())
t.Log("")
}
os.Stdout.Write([]byte("pprof.Lookup('goroutine'):\n"))
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
capture()
panic("Timed out waiting for all validators to commit a block")
}
}
func capture() {
trace := make([]byte, 10240000)
count := runtime.Stack(trace, true)
fmt.Printf("Stack of %d bytes: %s\n", count, trace)
}

View File

@ -2,25 +2,29 @@ package consensus
import (
"bytes"
"errors"
"encoding/json"
"fmt"
"hash/crc32"
"io"
"reflect"
"strconv"
"strings"
//"strconv"
//"strings"
"time"
abci "github.com/tendermint/abci/types"
auto "github.com/tendermint/go-autofile"
. "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
"github.com/tendermint/go-wire"
//auto "github.com/tendermint/tmlibs/autofile"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/version"
)
var crc32c = crc32.MakeTable(crc32.Castagnoli)
// Functionality to replay blocks and messages on recovery from a crash.
// There are two general failure scenarios: failure during consensus, and failure while applying the block.
// The former is handled by the WAL, the latter by the proxyApp Handshake on restart,
@ -34,23 +38,16 @@ import (
// as if it were received in receiveRoutine
// Lines that start with "#" are ignored.
// NOTE: receiveRoutine should not be running
func (cs *ConsensusState) readReplayMessage(msgBytes []byte, newStepCh chan interface{}) error {
// Skip over empty and meta lines
if len(msgBytes) == 0 || msgBytes[0] == '#' {
func (cs *ConsensusState) readReplayMessage(msg *TimedWALMessage, newStepCh chan interface{}) error {
// skip meta messages
if _, ok := msg.Msg.(EndHeightMessage); ok {
return nil
}
var err error
var msg TimedWALMessage
wire.ReadJSON(&msg, msgBytes, &err)
if err != nil {
fmt.Println("MsgBytes:", msgBytes, string(msgBytes))
return fmt.Errorf("Error reading json data: %v", err)
}
// for logging
switch m := msg.Msg.(type) {
case types.EventDataRoundState:
log.Notice("Replay: New Step", "height", m.Height, "round", m.Round, "step", m.Step)
cs.Logger.Info("Replay: New Step", "height", m.Height, "round", m.Round, "step", m.Step)
// these are playback checks
ticker := time.After(time.Second * 2)
if newStepCh != nil {
@ -65,26 +62,26 @@ func (cs *ConsensusState) readReplayMessage(msgBytes []byte, newStepCh chan inte
}
}
case msgInfo:
peerKey := m.PeerKey
if peerKey == "" {
peerKey = "local"
peerID := m.PeerID
if peerID == "" {
peerID = "local"
}
switch msg := m.Msg.(type) {
case *ProposalMessage:
p := msg.Proposal
log.Notice("Replay: Proposal", "height", p.Height, "round", p.Round, "header",
p.BlockPartsHeader, "pol", p.POLRound, "peer", peerKey)
cs.Logger.Info("Replay: Proposal", "height", p.Height, "round", p.Round, "header",
p.BlockPartsHeader, "pol", p.POLRound, "peer", peerID)
case *BlockPartMessage:
log.Notice("Replay: BlockPart", "height", msg.Height, "round", msg.Round, "peer", peerKey)
cs.Logger.Info("Replay: BlockPart", "height", msg.Height, "round", msg.Round, "peer", peerID)
case *VoteMessage:
v := msg.Vote
log.Notice("Replay: Vote", "height", v.Height, "round", v.Round, "type", v.Type,
"blockID", v.BlockID, "peer", peerKey)
cs.Logger.Info("Replay: Vote", "height", v.Height, "round", v.Round, "type", v.Type,
"blockID", v.BlockID, "peer", peerID)
}
cs.handleMsg(m, cs.RoundState)
cs.handleMsg(m)
case timeoutInfo:
log.Notice("Replay: Timeout", "height", m.Height, "round", m.Round, "step", m.Step, "dur", m.Duration)
cs.Logger.Info("Replay: Timeout", "height", m.Height, "round", m.Round, "step", m.Step, "dur", m.Duration)
cs.handleTimeout(m, cs.RoundState)
default:
return fmt.Errorf("Replay: Unknown TimedWALMessage type: %v", reflect.TypeOf(msg.Msg))
@ -94,77 +91,68 @@ func (cs *ConsensusState) readReplayMessage(msgBytes []byte, newStepCh chan inte
// replay only those messages since the last block.
// timeoutRoutine should run concurrently to read off tickChan
func (cs *ConsensusState) catchupReplay(csHeight int) error {
func (cs *ConsensusState) catchupReplay(csHeight int64) error {
// set replayMode
cs.replayMode = true
defer func() { cs.replayMode = false }()
// Ensure that ENDHEIGHT for this height doesn't exist
// NOTE: This is just a sanity check. As far as we know things work fine without it,
// and Handshake could reuse ConsensusState if it weren't for this check (since we can crash after writing ENDHEIGHT).
gr, found, err := cs.wal.group.Search("#ENDHEIGHT: ", makeHeightSearchFunc(csHeight))
// Ensure that ENDHEIGHT for this height doesn't exist.
// NOTE: This is just a sanity check. As far as we know things work fine
// without it, and Handshake could reuse ConsensusState if it weren't for
// this check (since we can crash after writing ENDHEIGHT).
//
// Ignore data corruption errors since this is a sanity check.
gr, found, err := cs.wal.SearchForEndHeight(csHeight, &WALSearchOptions{IgnoreDataCorruptionErrors: true})
if err != nil {
return err
}
if gr != nil {
gr.Close()
if err := gr.Close(); err != nil {
return err
}
}
if found {
return errors.New(Fmt("WAL should not contain #ENDHEIGHT %d.", csHeight))
return fmt.Errorf("WAL should not contain #ENDHEIGHT %d", csHeight)
}
// Search for last height marker
gr, found, err = cs.wal.group.Search("#ENDHEIGHT: ", makeHeightSearchFunc(csHeight-1))
//
// Ignore data corruption errors in previous heights because we only care about last height
gr, found, err = cs.wal.SearchForEndHeight(csHeight-1, &WALSearchOptions{IgnoreDataCorruptionErrors: true})
if err == io.EOF {
log.Warn("Replay: wal.group.Search returned EOF", "#ENDHEIGHT", csHeight-1)
// if we upgraded from 0.9 to 0.9.1, we may have #HEIGHT instead
// TODO (0.10.0): remove this
gr, found, err = cs.wal.group.Search("#HEIGHT: ", makeHeightSearchFunc(csHeight))
if err == io.EOF {
log.Warn("Replay: wal.group.Search returned EOF", "#HEIGHT", csHeight)
return nil
} else if err != nil {
return err
}
cs.Logger.Error("Replay: wal.group.Search returned EOF", "#ENDHEIGHT", csHeight-1)
} else if err != nil {
return err
} else {
defer gr.Close()
}
if !found {
// if we upgraded from 0.9 to 0.9.1, we may have #HEIGHT instead
// TODO (0.10.0): remove this
gr, found, err = cs.wal.group.Search("#HEIGHT: ", makeHeightSearchFunc(csHeight))
if err == io.EOF {
log.Warn("Replay: wal.group.Search returned EOF", "#HEIGHT", csHeight)
return nil
} else if err != nil {
return err
} else {
defer gr.Close()
}
// TODO (0.10.0): uncomment
// return errors.New(Fmt("Cannot replay height %d. WAL does not contain #ENDHEIGHT for %d.", csHeight, csHeight-1))
return fmt.Errorf("Cannot replay height %d. WAL does not contain #ENDHEIGHT for %d", csHeight, csHeight-1)
}
defer gr.Close() // nolint: errcheck
log.Notice("Catchup by replaying consensus messages", "height", csHeight)
cs.Logger.Info("Catchup by replaying consensus messages", "height", csHeight)
var msg *TimedWALMessage
dec := WALDecoder{gr}
for {
line, err := gr.ReadLine()
if err != nil {
if err == io.EOF {
break
} else {
return err
}
msg, err = dec.Decode()
if err == io.EOF {
break
} else if IsDataCorruptionError(err) {
cs.Logger.Debug("data has been corrupted in last height of consensus WAL", "err", err, "height", csHeight)
panic(fmt.Sprintf("data has been corrupted (%v) in last height %d of consensus WAL", err, csHeight))
} else if err != nil {
return err
}
// NOTE: since the priv key is set when the msgs are received
// it will attempt to eg double sign but we can just ignore it
// since the votes will be replayed and we'll get to the next step
if err := cs.readReplayMessage([]byte(line), nil); err != nil {
if err := cs.readReplayMessage(msg, nil); err != nil {
return err
}
}
log.Notice("Replay: Done")
cs.Logger.Info("Replay: Done")
return nil
}
@ -172,7 +160,8 @@ func (cs *ConsensusState) catchupReplay(csHeight int) error {
// Parses marker lines of the form:
// #ENDHEIGHT: 12345
func makeHeightSearchFunc(height int) auto.SearchFunc {
/*
func makeHeightSearchFunc(height int64) auto.SearchFunc {
return func(line string) (int, error) {
line = strings.TrimRight(line, "\n")
parts := strings.Split(line, " ")
@ -191,7 +180,7 @@ func makeHeightSearchFunc(height int) auto.SearchFunc {
return -1, nil
}
}
}
}*/
//----------------------------------------------
// Recover from failure during block processing
@ -199,49 +188,61 @@ func makeHeightSearchFunc(height int) auto.SearchFunc {
// we were last and using the WAL to recover there
type Handshaker struct {
config cfg.Config
state *sm.State
store types.BlockStore
stateDB dbm.DB
initialState sm.State
store types.BlockStore
appState json.RawMessage
logger log.Logger
nBlocks int // number of blocks applied to the state
}
func NewHandshaker(config cfg.Config, state *sm.State, store types.BlockStore) *Handshaker {
return &Handshaker{config, state, store, 0}
func NewHandshaker(stateDB dbm.DB, state sm.State,
store types.BlockStore, appState json.RawMessage) *Handshaker {
return &Handshaker{
stateDB: stateDB,
initialState: state,
store: store,
appState: appState,
logger: log.NewNopLogger(),
nBlocks: 0,
}
}
func (h *Handshaker) SetLogger(l log.Logger) {
h.logger = l
}
func (h *Handshaker) NBlocks() int {
return h.nBlocks
}
var ErrReplayLastBlockTimeout = errors.New("Timed out waiting for last block to be replayed")
// TODO: retry the handshake/replay if it fails ?
func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
// handshake is done via info request on the query conn
res, err := proxyApp.Query().InfoSync()
res, err := proxyApp.Query().InfoSync(abci.RequestInfo{version.Version})
if err != nil {
return errors.New(Fmt("Error calling Info: %v", err))
return fmt.Errorf("Error calling Info: %v", err)
}
blockHeight := int(res.LastBlockHeight) // XXX: beware overflow
blockHeight := int64(res.LastBlockHeight)
if blockHeight < 0 {
return fmt.Errorf("Got a negative last block height (%d) from the app", blockHeight)
}
appHash := res.LastBlockAppHash
log.Notice("ABCI Handshake", "appHeight", blockHeight, "appHash", appHash)
h.logger.Info("ABCI Handshake", "appHeight", blockHeight, "appHash", fmt.Sprintf("%X", appHash))
// TODO: check version
// replay blocks up to the latest in the blockstore
_, err = h.ReplayBlocks(appHash, blockHeight, proxyApp)
if err == ErrReplayLastBlockTimeout {
log.Warn("Failed to sync via handshake. Trying other means. If they fail, please increase the timeout_handshake parameter")
return nil
} else if err != nil {
return errors.New(Fmt("Error on replay: %v", err))
_, err = h.ReplayBlocks(h.initialState, appHash, blockHeight, proxyApp)
if err != nil {
return fmt.Errorf("Error on replay: %v", err)
}
log.Notice("Completed ABCI Handshake - Tendermint and App are synced", "appHeight", blockHeight, "appHash", appHash)
h.logger.Info("Completed ABCI Handshake - Tendermint and App are synced", "appHeight", blockHeight, "appHash", fmt.Sprintf("%X", appHash))
// TODO: (on restart) replay mempool
@ -250,15 +251,28 @@ func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
// Replay all blocks since appBlockHeight and ensure the result matches the current state.
// Returns the final AppHash or an error
func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int, proxyApp proxy.AppConns) ([]byte, error) {
func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight int64, proxyApp proxy.AppConns) ([]byte, error) {
storeBlockHeight := h.store.Height()
stateBlockHeight := h.state.LastBlockHeight
log.Notice("ABCI Replay Blocks", "appHeight", appBlockHeight, "storeHeight", storeBlockHeight, "stateHeight", stateBlockHeight)
stateBlockHeight := state.LastBlockHeight
h.logger.Info("ABCI Replay Blocks", "appHeight", appBlockHeight, "storeHeight", storeBlockHeight, "stateHeight", stateBlockHeight)
// If appBlockHeight == 0 it means that we are at genesis and hence should send InitChain
if appBlockHeight == 0 {
validators := types.TM2PB.Validators(state.Validators)
req := abci.RequestInitChain{
Validators: validators,
AppStateBytes: h.appState,
}
_, err := proxyApp.Consensus().InitChainSync(req)
if err != nil {
return nil, err
}
}
// First handle edge cases and constraints on the storeBlockHeight
if storeBlockHeight == 0 {
return appHash, h.checkAppHash(appHash)
return appHash, checkAppHash(state, appHash)
} else if storeBlockHeight < appBlockHeight {
// the app should never be ahead of the store (but this is under app's control)
@ -266,13 +280,14 @@ func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int, proxyApp p
} else if storeBlockHeight < stateBlockHeight {
// the state should never be ahead of the store (this is under tendermint's control)
PanicSanity(Fmt("StateBlockHeight (%d) > StoreBlockHeight (%d)", stateBlockHeight, storeBlockHeight))
cmn.PanicSanity(cmn.Fmt("StateBlockHeight (%d) > StoreBlockHeight (%d)", stateBlockHeight, storeBlockHeight))
} else if storeBlockHeight > stateBlockHeight+1 {
// store should be at most one ahead of the state (this is under tendermint's control)
PanicSanity(Fmt("StoreBlockHeight (%d) > StateBlockHeight + 1 (%d)", storeBlockHeight, stateBlockHeight+1))
cmn.PanicSanity(cmn.Fmt("StoreBlockHeight (%d) > StateBlockHeight + 1 (%d)", storeBlockHeight, stateBlockHeight+1))
}
var err error
// Now either store is equal to state, or one ahead.
// For each, consider all cases of where the app could be, given app <= store
if storeBlockHeight == stateBlockHeight {
@ -280,11 +295,11 @@ func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int, proxyApp p
// Either the app is asking for replay, or we're all synced up.
if appBlockHeight < storeBlockHeight {
// the app is behind, so replay blocks, but no need to go through WAL (state is already synced to store)
return h.replayBlocks(proxyApp, appBlockHeight, storeBlockHeight, false)
return h.replayBlocks(state, proxyApp, appBlockHeight, storeBlockHeight, false)
} else if appBlockHeight == storeBlockHeight {
// We're good!
return appHash, h.checkAppHash(appHash)
return appHash, checkAppHash(state, appHash)
}
} else if storeBlockHeight == stateBlockHeight+1 {
@ -293,83 +308,96 @@ func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int, proxyApp p
if appBlockHeight < stateBlockHeight {
// the app is further behind than it should be, so replay blocks
// but leave the last block to go through the WAL
return h.replayBlocks(proxyApp, appBlockHeight, storeBlockHeight, true)
return h.replayBlocks(state, proxyApp, appBlockHeight, storeBlockHeight, true)
} else if appBlockHeight == stateBlockHeight {
// We haven't run Commit (both the state and app are one block behind),
// so replayBlock with the real app.
// NOTE: We could instead use the cs.WAL on cs.Start,
// but we'd have to allow the WAL to replay a block that wrote it's ENDHEIGHT
log.Info("Replay last block using real app")
return h.replayBlock(storeBlockHeight, proxyApp.Consensus())
h.logger.Info("Replay last block using real app")
state, err = h.replayBlock(state, storeBlockHeight, proxyApp.Consensus())
return state.AppHash, err
} else if appBlockHeight == storeBlockHeight {
// We ran Commit, but didn't save the state, so replayBlock with mock app
abciResponses := h.state.LoadABCIResponses()
abciResponses, err := sm.LoadABCIResponses(h.stateDB, storeBlockHeight)
if err != nil {
return nil, err
}
mockApp := newMockProxyApp(appHash, abciResponses)
log.Info("Replay last block using mock app")
return h.replayBlock(storeBlockHeight, mockApp)
h.logger.Info("Replay last block using mock app")
state, err = h.replayBlock(state, storeBlockHeight, mockApp)
return state.AppHash, err
}
}
PanicSanity("Should never happen")
cmn.PanicSanity("Should never happen")
return nil, nil
}
func (h *Handshaker) replayBlocks(proxyApp proxy.AppConns, appBlockHeight, storeBlockHeight int, mutateState bool) ([]byte, error) {
func (h *Handshaker) replayBlocks(state sm.State, proxyApp proxy.AppConns, appBlockHeight, storeBlockHeight int64, mutateState bool) ([]byte, error) {
// App is further behind than it should be, so we need to replay blocks.
// We replay all blocks from appBlockHeight+1.
//
// Note that we don't have an old version of the state,
// so we by-pass state validation/mutation using sm.ExecCommitBlock.
// This also means we won't be saving validator sets if they change during this period.
// TODO: Load the historical information to fix this and just use state.ApplyBlock
//
// If mutateState == true, the final block is replayed with h.replayBlock()
var appHash []byte
var err error
finalBlock := storeBlockHeight
if mutateState {
finalBlock -= 1
finalBlock--
}
for i := appBlockHeight + 1; i <= finalBlock; i++ {
log.Info("Applying block", "height", i)
h.logger.Info("Applying block", "height", i)
block := h.store.LoadBlock(i)
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block)
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger)
if err != nil {
return nil, err
}
h.nBlocks += 1
h.nBlocks++
}
if mutateState {
// sync the final block
return h.replayBlock(storeBlockHeight, proxyApp.Consensus())
state, err = h.replayBlock(state, storeBlockHeight, proxyApp.Consensus())
if err != nil {
return nil, err
}
appHash = state.AppHash
}
return appHash, h.checkAppHash(appHash)
return appHash, checkAppHash(state, appHash)
}
// ApplyBlock on the proxyApp with the last block.
func (h *Handshaker) replayBlock(height int, proxyApp proxy.AppConnConsensus) ([]byte, error) {
mempool := types.MockMempool{}
var eventCache types.Fireable // nil
func (h *Handshaker) replayBlock(state sm.State, height int64, proxyApp proxy.AppConnConsensus) (sm.State, error) {
block := h.store.LoadBlock(height)
meta := h.store.LoadBlockMeta(height)
if err := h.state.ApplyBlock(eventCache, proxyApp, block, meta.BlockID.PartsHeader, mempool); err != nil {
return nil, err
blockExec := sm.NewBlockExecutor(h.stateDB, h.logger, proxyApp, types.MockMempool{}, types.MockEvidencePool{})
var err error
state, err = blockExec.ApplyBlock(state, meta.BlockID, block)
if err != nil {
return sm.State{}, err
}
h.nBlocks += 1
h.nBlocks++
return h.state.AppHash, nil
return state, nil
}
func (h *Handshaker) checkAppHash(appHash []byte) error {
if !bytes.Equal(h.state.AppHash, appHash) {
panic(errors.New(Fmt("Tendermint state.AppHash does not match AppHash after replay. Got %X, expected %X", appHash, h.state.AppHash)).Error())
return nil
func checkAppHash(state sm.State, appHash []byte) error {
if !bytes.Equal(state.AppHash, appHash) {
panic(fmt.Errorf("Tendermint state.AppHash does not match AppHash after replay. Got %X, expected %X", appHash, state.AppHash).Error())
}
return nil
}
@ -384,6 +412,10 @@ func newMockProxyApp(appHash []byte, abciResponses *sm.ABCIResponses) proxy.AppC
abciResponses: abciResponses,
})
cli, _ := clientCreator.NewABCIClient()
err := cli.Start()
if err != nil {
panic(err)
}
return proxy.NewAppConnConsensus(cli)
}
@ -395,21 +427,17 @@ type mockProxyApp struct {
abciResponses *sm.ABCIResponses
}
func (mock *mockProxyApp) DeliverTx(tx []byte) abci.Result {
func (mock *mockProxyApp) DeliverTx(tx []byte) abci.ResponseDeliverTx {
r := mock.abciResponses.DeliverTx[mock.txCount]
mock.txCount += 1
return abci.Result{
r.Code,
r.Data,
r.Log,
}
mock.txCount++
return *r
}
func (mock *mockProxyApp) EndBlock(height uint64) abci.ResponseEndBlock {
func (mock *mockProxyApp) EndBlock(req abci.RequestEndBlock) abci.ResponseEndBlock {
mock.txCount = 0
return mock.abciResponses.EndBlock
return *mock.abciResponses.EndBlock
}
func (mock *mockProxyApp) Commit() abci.Result {
return abci.NewResultOK(mock.appHash, "")
func (mock *mockProxyApp) Commit() abci.ResponseCommit {
return abci.ResponseCommit{Data: mock.appHash}
}

View File

@ -2,30 +2,38 @@ package consensus
import (
"bufio"
"errors"
"context"
"fmt"
"io"
"os"
"strconv"
"strings"
. "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
dbm "github.com/tendermint/go-db"
"github.com/pkg/errors"
bc "github.com/tendermint/tendermint/blockchain"
mempl "github.com/tendermint/tendermint/mempool"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
)
const (
// event bus subscriber
subscriber = "replay-file"
)
//--------------------------------------------------------
// replay messages interactively or all at once
func RunReplayFile(config cfg.Config, walFile string, console bool) {
consensusState := newConsensusStateForReplay(config)
func RunReplayFile(config cfg.BaseConfig, csConfig *cfg.ConsensusConfig, console bool) {
consensusState := newConsensusStateForReplay(config, csConfig)
if err := consensusState.ReplayFile(walFile, console); err != nil {
Exit(Fmt("Error during consensus replay: %v", err))
if err := consensusState.ReplayFile(csConfig.WalFile(), console); err != nil {
cmn.Exit(cmn.Fmt("Error during consensus replay: %v", err))
}
}
@ -42,31 +50,46 @@ func (cs *ConsensusState) ReplayFile(file string, console bool) error {
cs.startForReplay()
// ensure all new step events are regenerated as expected
newStepCh := subscribeToEvent(cs.evsw, "replay-test", types.EventStringNewRoundStep(), 1)
newStepCh := make(chan interface{}, 1)
ctx := context.Background()
err := cs.eventBus.Subscribe(ctx, subscriber, types.EventQueryNewRoundStep, newStepCh)
if err != nil {
return errors.Errorf("failed to subscribe %s to %v", subscriber, types.EventQueryNewRoundStep)
}
defer cs.eventBus.Unsubscribe(ctx, subscriber, types.EventQueryNewRoundStep)
// just open the file for reading, no need to use wal
fp, err := os.OpenFile(file, os.O_RDONLY, 0666)
fp, err := os.OpenFile(file, os.O_RDONLY, 0600)
if err != nil {
return err
}
pb := newPlayback(file, fp, cs, cs.state.Copy())
defer pb.fp.Close()
defer pb.fp.Close() // nolint: errcheck
var nextN int // apply N msgs in a row
for pb.scanner.Scan() {
var msg *TimedWALMessage
for {
if nextN == 0 && console {
nextN = pb.replayConsoleLoop()
}
if err := pb.cs.readReplayMessage(pb.scanner.Bytes(), newStepCh); err != nil {
msg, err = pb.dec.Decode()
if err == io.EOF {
return nil
} else if err != nil {
return err
}
if err := pb.cs.readReplayMessage(msg, newStepCh); err != nil {
return err
}
if nextN > 0 {
nextN -= 1
nextN--
}
pb.count += 1
pb.count++
}
return nil
}
@ -77,58 +100,66 @@ func (cs *ConsensusState) ReplayFile(file string, console bool) error {
type playback struct {
cs *ConsensusState
fp *os.File
scanner *bufio.Scanner
count int // how many lines/msgs into the file are we
fp *os.File
dec *WALDecoder
count int // how many lines/msgs into the file are we
// replays can be reset to beginning
fileName string // so we can close/reopen the file
genesisState *sm.State // so the replay session knows where to restart from
fileName string // so we can close/reopen the file
genesisState sm.State // so the replay session knows where to restart from
}
func newPlayback(fileName string, fp *os.File, cs *ConsensusState, genState *sm.State) *playback {
func newPlayback(fileName string, fp *os.File, cs *ConsensusState, genState sm.State) *playback {
return &playback{
cs: cs,
fp: fp,
fileName: fileName,
genesisState: genState,
scanner: bufio.NewScanner(fp),
dec: NewWALDecoder(fp),
}
}
// go back count steps by resetting the state and running (pb.count - count) steps
func (pb *playback) replayReset(count int, newStepCh chan interface{}) error {
pb.cs.Stop()
pb.cs.Wait()
newCS := NewConsensusState(pb.cs.config, pb.genesisState.Copy(), pb.cs.proxyAppConn, pb.cs.blockStore, pb.cs.mempool)
newCS.SetEventSwitch(pb.cs.evsw)
newCS := NewConsensusState(pb.cs.config, pb.genesisState.Copy(), pb.cs.blockExec,
pb.cs.blockStore, pb.cs.mempool, pb.cs.evpool)
newCS.SetEventBus(pb.cs.eventBus)
newCS.startForReplay()
pb.fp.Close()
fp, err := os.OpenFile(pb.fileName, os.O_RDONLY, 0666)
if err := pb.fp.Close(); err != nil {
return err
}
fp, err := os.OpenFile(pb.fileName, os.O_RDONLY, 0600)
if err != nil {
return err
}
pb.fp = fp
pb.scanner = bufio.NewScanner(fp)
pb.dec = NewWALDecoder(fp)
count = pb.count - count
log.Notice(Fmt("Reseting from %d to %d", pb.count, count))
fmt.Printf("Reseting from %d to %d\n", pb.count, count)
pb.count = 0
pb.cs = newCS
for i := 0; pb.scanner.Scan() && i < count; i++ {
if err := pb.cs.readReplayMessage(pb.scanner.Bytes(), newStepCh); err != nil {
var msg *TimedWALMessage
for i := 0; i < count; i++ {
msg, err = pb.dec.Decode()
if err == io.EOF {
return nil
} else if err != nil {
return err
}
pb.count += 1
if err := pb.cs.readReplayMessage(msg, newStepCh); err != nil {
return err
}
pb.count++
}
return nil
}
func (cs *ConsensusState) startForReplay() {
log.Warn("Replay commands are disabled until someone updates them and writes tests")
cs.Logger.Error("Replay commands are disabled until someone updates them and writes tests")
/* TODO:!
// since we replay tocks we just ignore ticks
go func() {
@ -149,9 +180,9 @@ func (pb *playback) replayConsoleLoop() int {
bufReader := bufio.NewReader(os.Stdin)
line, more, err := bufReader.ReadLine()
if more {
Exit("input is too long")
cmn.Exit("input is too long")
} else if err != nil {
Exit(err.Error())
cmn.Exit(err.Error())
}
tokens := strings.Split(string(line), " ")
@ -166,13 +197,12 @@ func (pb *playback) replayConsoleLoop() int {
if len(tokens) == 1 {
return 0
}
i, err := strconv.Atoi(tokens[1])
if err != nil {
fmt.Println("next takes an integer argument")
} else {
i, err := strconv.Atoi(tokens[1])
if err != nil {
fmt.Println("next takes an integer argument")
} else {
return i
}
return i
}
case "back":
@ -182,10 +212,20 @@ func (pb *playback) replayConsoleLoop() int {
// NOTE: "back" is not supported in the state machine design,
// so we restart and replay up to
ctx := context.Background()
// ensure all new step events are regenerated as expected
newStepCh := subscribeToEvent(pb.cs.evsw, "replay-test", types.EventStringNewRoundStep(), 1)
newStepCh := make(chan interface{}, 1)
err := pb.cs.eventBus.Subscribe(ctx, subscriber, types.EventQueryNewRoundStep, newStepCh)
if err != nil {
cmn.Exit(fmt.Sprintf("failed to subscribe %s to %v", subscriber, types.EventQueryNewRoundStep))
}
defer pb.cs.eventBus.Unsubscribe(ctx, subscriber, types.EventQueryNewRoundStep)
if len(tokens) == 1 {
pb.replayReset(1, newStepCh)
if err := pb.replayReset(1, newStepCh); err != nil {
pb.cs.Logger.Error("Replay reset error", "err", err)
}
} else {
i, err := strconv.Atoi(tokens[1])
if err != nil {
@ -193,7 +233,9 @@ func (pb *playback) replayConsoleLoop() int {
} else if i > pb.count {
fmt.Printf("argument to back must not be larger than the current count (%d)\n", pb.count)
} else {
pb.replayReset(i, newStepCh)
if err := pb.replayReset(i, newStepCh); err != nil {
pb.cs.Logger.Error("Replay reset error", "err", err)
}
}
}
@ -236,34 +278,43 @@ func (pb *playback) replayConsoleLoop() int {
//--------------------------------------------------------------------------------
// convenience for replay mode
func newConsensusStateForReplay(config cfg.Config) *ConsensusState {
func newConsensusStateForReplay(config cfg.BaseConfig, csConfig *cfg.ConsensusConfig) *ConsensusState {
dbType := dbm.DBBackendType(config.DBBackend)
// Get BlockStore
blockStoreDB := dbm.NewDB("blockstore", config.GetString("db_backend"), config.GetString("db_dir"))
blockStoreDB := dbm.NewDB("blockstore", dbType, config.DBDir())
blockStore := bc.NewBlockStore(blockStoreDB)
// Get State
stateDB := dbm.NewDB("state", config.GetString("db_backend"), config.GetString("db_dir"))
state := sm.MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
stateDB := dbm.NewDB("state", dbType, config.DBDir())
gdoc, err := sm.MakeGenesisDocFromFile(config.GenesisFile())
if err != nil {
cmn.Exit(err.Error())
}
state, err := sm.MakeGenesisState(gdoc)
if err != nil {
cmn.Exit(err.Error())
}
// Create proxyAppConn connection (consensus, mempool, query)
proxyApp := proxy.NewAppConns(config, proxy.DefaultClientCreator(config), NewHandshaker(config, state, blockStore))
_, err := proxyApp.Start()
clientCreator := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir())
proxyApp := proxy.NewAppConns(clientCreator,
NewHandshaker(stateDB, state, blockStore, gdoc.AppState()))
err = proxyApp.Start()
if err != nil {
Exit(Fmt("Error starting proxy app conns: %v", err))
cmn.Exit(cmn.Fmt("Error starting proxy app conns: %v", err))
}
// add the chainid to the global config
config.Set("chain_id", state.ChainID)
// Make event switch
eventSwitch := types.NewEventSwitch()
if _, err := eventSwitch.Start(); err != nil {
Exit(Fmt("Failed to start event switch: %v", err))
eventBus := types.NewEventBus()
if err := eventBus.Start(); err != nil {
cmn.Exit(cmn.Fmt("Failed to start event bus: %v", err))
}
mempool := mempl.NewMempool(config, proxyApp.Mempool())
mempool, evpool := types.MockMempool{}, types.MockEvidencePool{}
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
consensusState := NewConsensusState(config, state.Copy(), proxyApp.Consensus(), blockStore, mempool)
consensusState.SetEventSwitch(eventSwitch)
consensusState := NewConsensusState(csConfig, state.Copy(), blockExec,
blockStore, mempool, evpool)
consensusState.SetEventBus(eventBus)
return consensusState
}

View File

@ -2,31 +2,38 @@ package consensus
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"strings"
"runtime"
"testing"
"time"
"github.com/tendermint/tendermint/config/tendermint_test"
"github.com/stretchr/testify/require"
"github.com/tendermint/abci/example/dummy"
cmn "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
"github.com/tendermint/abci/example/kvstore"
abci "github.com/tendermint/abci/types"
"github.com/tendermint/go-crypto"
dbm "github.com/tendermint/go-db"
"github.com/tendermint/go-wire"
auto "github.com/tendermint/tmlibs/autofile"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
"github.com/tendermint/tmlibs/log"
)
var consensusReplayConfig *cfg.Config
func init() {
config = tendermint_test.ResetConfig("consensus_replay_test")
consensusReplayConfig = ResetConfig("consensus_replay_test")
}
// These tests ensure we can always recover from failure at any part of the consensus process.
@ -37,8 +44,6 @@ func init() {
// the `Handshake Tests` are for failures in applying the block.
// With the help of the WAL, we can recover from it all!
var data_dir = path.Join(cmn.GoPath, "src/github.com/tendermint/tendermint/consensus", "test_data")
//------------------------------------------------------------------------------------------
// WAL Tests
@ -46,217 +51,216 @@ var data_dir = path.Join(cmn.GoPath, "src/github.com/tendermint/tendermint/conse
// and which ones we need the wal for - then we'd also be able to only flush the
// wal writer when we need to, instead of with every message.
// the priv validator changes step at these lines for a block with 1 val and 1 part
var baseStepChanges = []int{3, 6, 8}
func startNewConsensusStateAndWaitForBlock(t *testing.T, lastBlockHeight int64, blockDB dbm.DB, stateDB dbm.DB) {
logger := log.TestingLogger()
state, _ := sm.LoadStateFromDBOrGenesisFile(stateDB, consensusReplayConfig.GenesisFile())
privValidator := loadPrivValidator(consensusReplayConfig)
cs := newConsensusStateWithConfigAndBlockStore(consensusReplayConfig, state, privValidator, kvstore.NewKVStoreApplication(), blockDB)
cs.SetLogger(logger)
// test recovery from each line in each testCase
var testCases = []*testCase{
newTestCase("empty_block", baseStepChanges), // empty block (has 1 block part)
newTestCase("small_block1", baseStepChanges), // small block with txs in 1 block part
newTestCase("small_block2", []int{3, 10, 12}), // small block with txs across 5 smaller block parts
}
bytes, _ := ioutil.ReadFile(cs.config.WalFile())
// fmt.Printf("====== WAL: \n\r%s\n", bytes)
t.Logf("====== WAL: \n\r%X\n", bytes)
type testCase struct {
name string
log string //full cs wal
stepMap map[int]int8 // map lines of log to privval step
err := cs.Start()
require.NoError(t, err)
defer cs.Stop()
proposeLine int
prevoteLine int
precommitLine int
}
func newTestCase(name string, stepChanges []int) *testCase {
if len(stepChanges) != 3 {
panic(cmn.Fmt("a full wal has 3 step changes! Got array %v", stepChanges))
}
return &testCase{
name: name,
log: readWAL(path.Join(data_dir, name+".cswal")),
stepMap: newMapFromChanges(stepChanges),
proposeLine: stepChanges[0],
prevoteLine: stepChanges[1],
precommitLine: stepChanges[2],
}
}
func newMapFromChanges(changes []int) map[int]int8 {
changes = append(changes, changes[2]+1) // so we add the last step change to the map
m := make(map[int]int8)
var count int
for changeNum, nextChange := range changes {
for ; count < nextChange; count++ {
m[count] = int8(changeNum)
}
}
return m
}
func readWAL(p string) string {
b, err := ioutil.ReadFile(p)
if err != nil {
panic(err)
}
return string(b)
}
func writeWAL(walMsgs string) string {
tempDir := os.TempDir()
walDir := path.Join(tempDir, "/wal"+cmn.RandStr(12))
walFile := path.Join(walDir, "wal")
// Create WAL directory
err := cmn.EnsureDir(walDir, 0700)
if err != nil {
panic(err)
}
// Write the needed WAL to file
err = cmn.WriteFile(walFile, []byte(walMsgs), 0600)
if err != nil {
panic(err)
}
return walFile
}
func waitForBlock(newBlockCh chan interface{}, thisCase *testCase, i int) {
after := time.After(time.Second * 10)
// This is just a signal that we haven't halted; its not something contained
// in the WAL itself. Assuming the consensus state is running, replay of any
// WAL, including the empty one, should eventually be followed by a new
// block, or else something is wrong.
newBlockCh := make(chan interface{}, 1)
err = cs.eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock, newBlockCh)
require.NoError(t, err)
select {
case <-newBlockCh:
case <-after:
panic(cmn.Fmt("Timed out waiting for new block for case '%s' line %d", thisCase.name, i))
case <-time.After(60 * time.Second):
t.Fatalf("Timed out waiting for new block (see trace above)")
}
}
func runReplayTest(t *testing.T, cs *ConsensusState, walFile string, newBlockCh chan interface{},
thisCase *testCase, i int) {
func sendTxs(cs *ConsensusState, ctx context.Context) {
for i := 0; i < 256; i++ {
select {
case <-ctx.Done():
return
default:
tx := []byte{byte(i)}
cs.mempool.CheckTx(tx, nil)
i++
}
}
}
cs.config.Set("cs_wal_file", walFile)
cs.Start()
// Wait to make a new block.
// This is just a signal that we haven't halted; its not something contained in the WAL itself.
// Assuming the consensus state is running, replay of any WAL, including the empty one,
// should eventually be followed by a new block, or else something is wrong
waitForBlock(newBlockCh, thisCase, i)
cs.evsw.Stop()
cs.Stop()
// TestWALCrash uses crashing WAL to test we can recover from any WAL failure.
func TestWALCrash(t *testing.T) {
testCases := []struct {
name string
initFn func(dbm.DB, *ConsensusState, context.Context)
heightToStop int64
}{
{"empty block",
func(stateDB dbm.DB, cs *ConsensusState, ctx context.Context) {},
1},
{"block with a smaller part size",
func(stateDB dbm.DB, cs *ConsensusState, ctx context.Context) {
// XXX: is there a better way to change BlockPartSizeBytes?
cs.state.ConsensusParams.BlockPartSizeBytes = 512
sm.SaveState(stateDB, cs.state)
go sendTxs(cs, ctx)
},
1},
{"many non-empty blocks",
func(stateDB dbm.DB, cs *ConsensusState, ctx context.Context) {
go sendTxs(cs, ctx)
},
3},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
crashWALandCheckLiveness(t, tc.initFn, tc.heightToStop)
})
}
}
func crashWALandCheckLiveness(t *testing.T, initFn func(dbm.DB, *ConsensusState, context.Context), heightToStop int64) {
walPaniced := make(chan error)
crashingWal := &crashingWAL{panicCh: walPaniced, heightToStop: heightToStop}
i := 1
LOOP:
for {
// fmt.Printf("====== LOOP %d\n", i)
t.Logf("====== LOOP %d\n", i)
// create consensus state from a clean slate
logger := log.NewNopLogger()
stateDB := dbm.NewMemDB()
state, _ := sm.MakeGenesisStateFromFile(consensusReplayConfig.GenesisFile())
privValidator := loadPrivValidator(consensusReplayConfig)
blockDB := dbm.NewMemDB()
cs := newConsensusStateWithConfigAndBlockStore(consensusReplayConfig, state, privValidator, kvstore.NewKVStoreApplication(), blockDB)
cs.SetLogger(logger)
// start sending transactions
ctx, cancel := context.WithCancel(context.Background())
initFn(stateDB, cs, ctx)
// clean up WAL file from the previous iteration
walFile := cs.config.WalFile()
os.Remove(walFile)
// set crashing WAL
csWal, err := cs.OpenWAL(walFile)
require.NoError(t, err)
crashingWal.next = csWal
// reset the message counter
crashingWal.msgIndex = 1
cs.wal = crashingWal
// start consensus state
err = cs.Start()
require.NoError(t, err)
i++
select {
case <-newBlockCh:
default:
break LOOP
}
}
cs.Wait()
}
case err := <-walPaniced:
t.Logf("WAL paniced: %v", err)
func toPV(pv PrivValidator) *types.PrivValidator {
return pv.(*types.PrivValidator)
}
// make sure we can make blocks after a crash
startNewConsensusStateAndWaitForBlock(t, cs.Height, blockDB, stateDB)
func setupReplayTest(thisCase *testCase, nLines int, crashAfter bool) (*ConsensusState, chan interface{}, string, string) {
fmt.Println("-------------------------------------")
log.Notice(cmn.Fmt("Starting replay test %v (of %d lines of WAL). Crash after = %v", thisCase.name, nLines, crashAfter))
// stop consensus state and transactions sender (initFn)
cs.Stop()
cancel()
lineStep := nLines
if crashAfter {
lineStep -= 1
}
split := strings.Split(thisCase.log, "\n")
lastMsg := split[nLines]
// we write those lines up to (not including) one with the signature
walFile := writeWAL(strings.Join(split[:nLines], "\n") + "\n")
cs := fixedConsensusStateDummy()
// set the last step according to when we crashed vs the wal
toPV(cs.privValidator).LastHeight = 1 // first block
toPV(cs.privValidator).LastStep = thisCase.stepMap[lineStep]
log.Warn("setupReplayTest", "LastStep", toPV(cs.privValidator).LastStep)
newBlockCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewBlock(), 1)
return cs, newBlockCh, lastMsg, walFile
}
func readTimedWALMessage(t *testing.T, walMsg string) TimedWALMessage {
var err error
var msg TimedWALMessage
wire.ReadJSON(&msg, []byte(walMsg), &err)
if err != nil {
t.Fatalf("Error reading json data: %v", err)
}
return msg
}
//-----------------------------------------------
// Test the log at every iteration, and set the privVal last step
// as if the log was written after signing, before the crash
func TestWALCrashAfterWrite(t *testing.T) {
for _, thisCase := range testCases {
split := strings.Split(thisCase.log, "\n")
for i := 0; i < len(split)-1; i++ {
cs, newBlockCh, _, walFile := setupReplayTest(thisCase, i+1, true)
runReplayTest(t, cs, walFile, newBlockCh, thisCase, i+1)
// if we reached the required height, exit
if _, ok := err.(ReachedHeightToStopError); ok {
break LOOP
}
case <-time.After(10 * time.Second):
t.Fatal("WAL did not panic for 10 seconds (check the log)")
}
}
}
//-----------------------------------------------
// Test the log as if we crashed after signing but before writing.
// This relies on privValidator.LastSignature being set
// crashingWAL is a WAL which crashes or rather simulates a crash during Save
// (before and after). It remembers a message for which we last panicked
// (lastPanicedForMsgIndex), so we don't panic for it in subsequent iterations.
type crashingWAL struct {
next WAL
panicCh chan error
heightToStop int64
func TestWALCrashBeforeWritePropose(t *testing.T) {
for _, thisCase := range testCases {
lineNum := thisCase.proposeLine
// setup replay test where last message is a proposal
cs, newBlockCh, proposalMsg, walFile := setupReplayTest(thisCase, lineNum, false)
msg := readTimedWALMessage(t, proposalMsg)
proposal := msg.Msg.(msgInfo).Msg.(*ProposalMessage)
// Set LastSig
toPV(cs.privValidator).LastSignBytes = types.SignBytes(cs.state.ChainID, proposal.Proposal)
toPV(cs.privValidator).LastSignature = proposal.Proposal.Signature
runReplayTest(t, cs, walFile, newBlockCh, thisCase, lineNum)
msgIndex int // current message index
lastPanicedForMsgIndex int // last message for which we panicked
}
// WALWriteError indicates a WAL crash.
type WALWriteError struct {
msg string
}
func (e WALWriteError) Error() string {
return e.msg
}
// ReachedHeightToStopError indicates we've reached the required consensus
// height and may exit.
type ReachedHeightToStopError struct {
height int64
}
func (e ReachedHeightToStopError) Error() string {
return fmt.Sprintf("reached height to stop %d", e.height)
}
// Save simulate WAL's crashing by sending an error to the panicCh and then
// exiting the cs.receiveRoutine.
func (w *crashingWAL) Save(m WALMessage) {
if endMsg, ok := m.(EndHeightMessage); ok {
if endMsg.Height == w.heightToStop {
w.panicCh <- ReachedHeightToStopError{endMsg.Height}
runtime.Goexit()
} else {
w.next.Save(m)
}
return
}
if w.msgIndex > w.lastPanicedForMsgIndex {
w.lastPanicedForMsgIndex = w.msgIndex
_, file, line, _ := runtime.Caller(1)
w.panicCh <- WALWriteError{fmt.Sprintf("failed to write %T to WAL (fileline: %s:%d)", m, file, line)}
runtime.Goexit()
} else {
w.msgIndex++
w.next.Save(m)
}
}
func TestWALCrashBeforeWritePrevote(t *testing.T) {
for _, thisCase := range testCases {
testReplayCrashBeforeWriteVote(t, thisCase, thisCase.prevoteLine, types.EventStringCompleteProposal())
}
func (w *crashingWAL) Group() *auto.Group { return w.next.Group() }
func (w *crashingWAL) SearchForEndHeight(height int64, options *WALSearchOptions) (gr *auto.GroupReader, found bool, err error) {
return w.next.SearchForEndHeight(height, options)
}
func TestWALCrashBeforeWritePrecommit(t *testing.T) {
for _, thisCase := range testCases {
testReplayCrashBeforeWriteVote(t, thisCase, thisCase.precommitLine, types.EventStringPolka())
}
}
func testReplayCrashBeforeWriteVote(t *testing.T, thisCase *testCase, lineNum int, eventString string) {
// setup replay test where last message is a vote
cs, newBlockCh, voteMsg, walFile := setupReplayTest(thisCase, lineNum, false)
types.AddListenerForEvent(cs.evsw, "tester", eventString, func(data types.TMEventData) {
msg := readTimedWALMessage(t, voteMsg)
vote := msg.Msg.(msgInfo).Msg.(*VoteMessage)
// Set LastSig
toPV(cs.privValidator).LastSignBytes = types.SignBytes(cs.state.ChainID, vote.Vote)
toPV(cs.privValidator).LastSignature = vote.Vote.Signature
})
runReplayTest(t, cs, walFile, newBlockCh, thisCase, lineNum)
}
func (w *crashingWAL) Start() error { return w.next.Start() }
func (w *crashingWAL) Stop() error { return w.next.Stop() }
func (w *crashingWAL) Wait() { w.next.Wait() }
//------------------------------------------------------------------------------------------
// Handshake Tests
var (
NUM_BLOCKS = 6 // number of blocks in the test_data/many_blocks.cswal
mempool = types.MockMempool{}
const (
NUM_BLOCKS = 6
)
testPartSize int
var (
mempool = types.MockMempool{}
evpool = types.MockEvidencePool{}
)
//---------------------------------------
@ -295,57 +299,78 @@ func TestHandshakeReplayNone(t *testing.T) {
}
}
func tempWALWithData(data []byte) string {
walFile, err := ioutil.TempFile("", "wal")
if err != nil {
panic(fmt.Errorf("failed to create temp WAL file: %v", err))
}
_, err = walFile.Write(data)
if err != nil {
panic(fmt.Errorf("failed to write to temp WAL file: %v", err))
}
if err := walFile.Close(); err != nil {
panic(fmt.Errorf("failed to close temp WAL file: %v", err))
}
return walFile.Name()
}
// Make some blocks. Start a fresh app and apply nBlocks blocks. Then restart the app and sync it up with the remaining blocks
func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
config := tendermint_test.ResetConfig("proxy_test_")
config := ResetConfig("proxy_test_")
// copy the many_blocks file
walBody, err := cmn.ReadFile(path.Join(data_dir, "many_blocks.cswal"))
walBody, err := WALWithNBlocks(NUM_BLOCKS)
if err != nil {
t.Fatal(err)
}
walFile := writeWAL(string(walBody))
config.Set("cs_wal_file", walFile)
walFile := tempWALWithData(walBody)
config.Consensus.SetWalFile(walFile)
privVal := types.LoadPrivValidator(config.GetString("priv_validator_file"))
testPartSize = config.GetInt("block_part_size")
privVal := pvm.LoadFilePV(config.PrivValidatorFile())
wal, err := NewWAL(walFile, false)
if err != nil {
t.Fatal(err)
}
wal.SetLogger(log.TestingLogger())
if err := wal.Start(); err != nil {
t.Fatal(err)
}
defer wal.Stop()
chain, commits, err := makeBlockchainFromWAL(wal)
if err != nil {
t.Fatalf(err.Error())
}
state, store := stateAndStore(config, privVal.PubKey)
stateDB, state, store := stateAndStore(config, privVal.GetPubKey())
store.chain = chain
store.commits = commits
// run the chain through state.ApplyBlock to build up the tendermint state
latestAppHash := buildTMStateFromChain(config, state, chain, mode)
state = buildTMStateFromChain(config, stateDB, state, chain, mode)
latestAppHash := state.AppHash
// make a new client creator
dummyApp := dummy.NewPersistentDummyApplication(path.Join(config.GetString("db_dir"), "2"))
clientCreator2 := proxy.NewLocalClientCreator(dummyApp)
kvstoreApp := kvstore.NewPersistentKVStoreApplication(path.Join(config.DBDir(), "2"))
clientCreator2 := proxy.NewLocalClientCreator(kvstoreApp)
if nBlocks > 0 {
// run nBlocks against a new client to build up the app state.
// use a throwaway tendermint state
proxyApp := proxy.NewAppConns(config, clientCreator2, nil)
state, _ := stateAndStore(config, privVal.PubKey)
buildAppStateFromChain(proxyApp, state, chain, nBlocks, mode)
proxyApp := proxy.NewAppConns(clientCreator2, nil)
stateDB, state, _ := stateAndStore(config, privVal.GetPubKey())
buildAppStateFromChain(proxyApp, stateDB, state, chain, nBlocks, mode)
}
// now start the app using the handshake - it should sync
handshaker := NewHandshaker(config, state, store)
proxyApp := proxy.NewAppConns(config, clientCreator2, handshaker)
if _, err := proxyApp.Start(); err != nil {
handshaker := NewHandshaker(stateDB, state, store, nil)
proxyApp := proxy.NewAppConns(clientCreator2, handshaker)
if err := proxyApp.Start(); err != nil {
t.Fatalf("Error starting proxy app connections: %v", err)
}
defer proxyApp.Stop()
// get the latest app hash from the app
res, err := proxyApp.Query().InfoSync()
res, err := proxyApp.Query().InfoSync(abci.RequestInfo{""})
if err != nil {
t.Fatal(err)
}
@ -357,9 +382,9 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
expectedBlocksToSync := NUM_BLOCKS - nBlocks
if nBlocks == NUM_BLOCKS && mode > 0 {
expectedBlocksToSync += 1
expectedBlocksToSync++
} else if nBlocks > 0 && mode == 1 {
expectedBlocksToSync += 1
expectedBlocksToSync++
}
if handshaker.NBlocks() != expectedBlocksToSync {
@ -367,275 +392,240 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
}
}
func applyBlock(st *sm.State, blk *types.Block, proxyApp proxy.AppConns) {
err := st.ApplyBlock(nil, proxyApp.Consensus(), blk, blk.MakePartSet(testPartSize).Header(), mempool)
func applyBlock(stateDB dbm.DB, st sm.State, blk *types.Block, proxyApp proxy.AppConns) sm.State {
testPartSize := st.ConsensusParams.BlockPartSizeBytes
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
blkID := types.BlockID{blk.Hash(), blk.MakePartSet(testPartSize).Header()}
newState, err := blockExec.ApplyBlock(st, blkID, blk)
if err != nil {
panic(err)
}
return newState
}
func buildAppStateFromChain(proxyApp proxy.AppConns,
state *sm.State, chain []*types.Block, nBlocks int, mode uint) {
func buildAppStateFromChain(proxyApp proxy.AppConns, stateDB dbm.DB,
state sm.State, chain []*types.Block, nBlocks int, mode uint) {
// start a new app without handshake, play nBlocks blocks
if _, err := proxyApp.Start(); err != nil {
if err := proxyApp.Start(); err != nil {
panic(err)
}
defer proxyApp.Stop()
// TODO: get the genesis bytes (https://github.com/tendermint/tendermint/issues/1224)
var genesisBytes []byte
validators := types.TM2PB.Validators(state.Validators)
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators, genesisBytes}); err != nil {
panic(err)
}
switch mode {
case 0:
for i := 0; i < nBlocks; i++ {
block := chain[i]
applyBlock(state, block, proxyApp)
state = applyBlock(stateDB, state, block, proxyApp)
}
case 1, 2:
for i := 0; i < nBlocks-1; i++ {
block := chain[i]
applyBlock(state, block, proxyApp)
state = applyBlock(stateDB, state, block, proxyApp)
}
if mode == 2 {
// update the dummy height and apphash
// update the kvstore height and apphash
// as if we ran commit but not
applyBlock(state, chain[nBlocks-1], proxyApp)
state = applyBlock(stateDB, state, chain[nBlocks-1], proxyApp)
}
}
}
func buildTMStateFromChain(config cfg.Config, state *sm.State, chain []*types.Block, mode uint) []byte {
func buildTMStateFromChain(config *cfg.Config, stateDB dbm.DB, state sm.State, chain []*types.Block, mode uint) sm.State {
// run the whole chain against this client to build up the tendermint state
clientCreator := proxy.NewLocalClientCreator(dummy.NewPersistentDummyApplication(path.Join(config.GetString("db_dir"), "1")))
proxyApp := proxy.NewAppConns(config, clientCreator, nil) // sm.NewHandshaker(config, state, store, ReplayLastBlock))
if _, err := proxyApp.Start(); err != nil {
clientCreator := proxy.NewLocalClientCreator(kvstore.NewPersistentKVStoreApplication(path.Join(config.DBDir(), "1")))
proxyApp := proxy.NewAppConns(clientCreator, nil) // sm.NewHandshaker(config, state, store, ReplayLastBlock))
if err := proxyApp.Start(); err != nil {
panic(err)
}
defer proxyApp.Stop()
var latestAppHash []byte
// TODO: get the genesis bytes (https://github.com/tendermint/tendermint/issues/1224)
var genesisBytes []byte
validators := types.TM2PB.Validators(state.Validators)
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators, genesisBytes}); err != nil {
panic(err)
}
switch mode {
case 0:
// sync right up
for _, block := range chain {
applyBlock(state, block, proxyApp)
state = applyBlock(stateDB, state, block, proxyApp)
}
latestAppHash = state.AppHash
case 1, 2:
// sync up to the penultimate as if we stored the block.
// whether we commit or not depends on the appHash
for _, block := range chain[:len(chain)-1] {
applyBlock(state, block, proxyApp)
state = applyBlock(stateDB, state, block, proxyApp)
}
// apply the final block to a state copy so we can
// get the right next appHash but keep the state back
stateCopy := state.Copy()
applyBlock(stateCopy, chain[len(chain)-1], proxyApp)
latestAppHash = stateCopy.AppHash
applyBlock(stateDB, state, chain[len(chain)-1], proxyApp)
}
return latestAppHash
return state
}
//--------------------------
// utils for making blocks
func makeBlockchainFromWAL(wal *WAL) ([]*types.Block, []*types.Commit, error) {
func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
// Search for height marker
gr, found, err := wal.group.Search("#ENDHEIGHT: ", makeHeightSearchFunc(0))
gr, found, err := wal.SearchForEndHeight(0, &WALSearchOptions{})
if err != nil {
return nil, nil, err
}
if !found {
return nil, nil, errors.New(cmn.Fmt("WAL does not contain height %d.", 1))
}
defer gr.Close()
defer gr.Close() // nolint: errcheck
log.Notice("Build a blockchain by reading from the WAL")
// log.Notice("Build a blockchain by reading from the WAL")
var blockParts *types.PartSet
var blocks []*types.Block
var commits []*types.Commit
for {
line, err := gr.ReadLine()
if err != nil {
if err == io.EOF {
break
} else {
return nil, nil, err
}
}
piece, err := readPieceFromWAL([]byte(line))
if err != nil {
var thisBlockParts *types.PartSet
var thisBlockCommit *types.Commit
var height int64
dec := NewWALDecoder(gr)
for {
msg, err := dec.Decode()
if err == io.EOF {
break
} else if err != nil {
return nil, nil, err
}
piece := readPieceFromWAL(msg)
if piece == nil {
continue
}
switch p := piece.(type) {
case *types.PartSetHeader:
case EndHeightMessage:
// if its not the first one, we have a full block
if blockParts != nil {
var n int
block := wire.ReadBinary(&types.Block{}, blockParts.GetReader(), types.MaxBlockSize, &n, &err).(*types.Block)
if thisBlockParts != nil {
var block = new(types.Block)
_, err = cdc.UnmarshalBinaryReader(thisBlockParts.GetReader(), block, 0)
if err != nil {
panic(err)
}
if block.Height != height+1 {
panic(cmn.Fmt("read bad block from wal. got height %d, expected %d", block.Height, height+1))
}
commitHeight := thisBlockCommit.Precommits[0].Height
if commitHeight != height+1 {
panic(cmn.Fmt("commit doesnt match. got height %d, expected %d", commitHeight, height+1))
}
blocks = append(blocks, block)
commits = append(commits, thisBlockCommit)
height++
}
blockParts = types.NewPartSetFromHeader(*p)
case *types.PartSetHeader:
thisBlockParts = types.NewPartSetFromHeader(*p)
case *types.Part:
_, err := blockParts.AddPart(p, false)
_, err := thisBlockParts.AddPart(p, false)
if err != nil {
return nil, nil, err
}
case *types.Vote:
if p.Type == types.VoteTypePrecommit {
commit := &types.Commit{
thisBlockCommit = &types.Commit{
BlockID: p.BlockID,
Precommits: []*types.Vote{p},
}
commits = append(commits, commit)
}
}
}
// grab the last block too
var n int
block := wire.ReadBinary(&types.Block{}, blockParts.GetReader(), types.MaxBlockSize, &n, &err).(*types.Block)
var block = new(types.Block)
_, err = cdc.UnmarshalBinaryReader(thisBlockParts.GetReader(), block, 0)
if err != nil {
panic(err)
}
if block.Height != height+1 {
panic(cmn.Fmt("read bad block from wal. got height %d, expected %d", block.Height, height+1))
}
commitHeight := thisBlockCommit.Precommits[0].Height
if commitHeight != height+1 {
panic(cmn.Fmt("commit doesnt match. got height %d, expected %d", commitHeight, height+1))
}
blocks = append(blocks, block)
commits = append(commits, thisBlockCommit)
return blocks, commits, nil
}
func readPieceFromWAL(msgBytes []byte) (interface{}, error) {
// Skip over empty and meta lines
if len(msgBytes) == 0 || msgBytes[0] == '#' {
return nil, nil
}
var err error
var msg TimedWALMessage
wire.ReadJSON(&msg, msgBytes, &err)
if err != nil {
fmt.Println("MsgBytes:", msgBytes, string(msgBytes))
return nil, fmt.Errorf("Error reading json data: %v", err)
}
func readPieceFromWAL(msg *TimedWALMessage) interface{} {
// for logging
switch m := msg.Msg.(type) {
case msgInfo:
switch msg := m.Msg.(type) {
case *ProposalMessage:
return &msg.Proposal.BlockPartsHeader, nil
return &msg.Proposal.BlockPartsHeader
case *BlockPartMessage:
return msg.Part, nil
return msg.Part
case *VoteMessage:
return msg.Vote, nil
return msg.Vote
}
}
return nil, nil
}
// make some bogus txs
func txsFunc(blockNum int) (txs []types.Tx) {
for i := 0; i < 10; i++ {
txs = append(txs, types.Tx([]byte{byte(blockNum), byte(i)}))
}
return txs
}
// sign a commit vote
func signCommit(chainID string, privVal *types.PrivValidator, height, round int, hash []byte, header types.PartSetHeader) *types.Vote {
vote := &types.Vote{
ValidatorIndex: 0,
ValidatorAddress: privVal.Address,
Height: height,
Round: round,
Type: types.VoteTypePrecommit,
BlockID: types.BlockID{hash, header},
case EndHeightMessage:
return m
}
sig := privVal.Sign(types.SignBytes(chainID, vote))
vote.Signature = sig
return vote
}
// make a blockchain with one validator
func makeBlockchain(t *testing.T, chainID string, nBlocks int, privVal *types.PrivValidator, proxyApp proxy.AppConns, state *sm.State) (blockchain []*types.Block, commits []*types.Commit) {
prevHash := state.LastBlockID.Hash
lastCommit := new(types.Commit)
prevParts := types.PartSetHeader{}
valHash := state.Validators.Hash()
prevBlockID := types.BlockID{prevHash, prevParts}
for i := 1; i < nBlocks+1; i++ {
block, parts := types.MakeBlock(i, chainID, txsFunc(i), lastCommit,
prevBlockID, valHash, state.AppHash, testPartSize)
fmt.Println(i)
fmt.Println(block.LastBlockID)
err := state.ApplyBlock(nil, proxyApp.Consensus(), block, block.MakePartSet(testPartSize).Header(), mempool)
if err != nil {
t.Fatal(i, err)
}
voteSet := types.NewVoteSet(chainID, i, 0, types.VoteTypePrecommit, state.Validators)
vote := signCommit(chainID, privVal, i, 0, block.Hash(), parts.Header())
_, err = voteSet.AddVote(vote)
if err != nil {
t.Fatal(err)
}
prevHash = block.Hash()
prevParts = parts.Header()
lastCommit = voteSet.MakeCommit()
prevBlockID = types.BlockID{prevHash, prevParts}
blockchain = append(blockchain, block)
commits = append(commits, lastCommit)
}
return blockchain, commits
return nil
}
// fresh state and mock store
func stateAndStore(config cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBlockStore) {
func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (dbm.DB, sm.State, *mockBlockStore) {
stateDB := dbm.NewMemDB()
return sm.MakeGenesisState(stateDB, &types.GenesisDoc{
ChainID: config.GetString("chain_id"),
Validators: []types.GenesisValidator{
types.GenesisValidator{pubKey, 10000, "test"},
},
AppHash: nil,
}), NewMockBlockStore(config)
state, _ := sm.MakeGenesisStateFromFile(config.GenesisFile())
store := NewMockBlockStore(config, state.ConsensusParams)
return stateDB, state, store
}
//----------------------------------
// mock block store
type mockBlockStore struct {
config cfg.Config
config *cfg.Config
params types.ConsensusParams
chain []*types.Block
commits []*types.Commit
}
// TODO: NewBlockStore(db.NewMemDB) ...
func NewMockBlockStore(config cfg.Config) *mockBlockStore {
return &mockBlockStore{config, nil, nil}
func NewMockBlockStore(config *cfg.Config, params types.ConsensusParams) *mockBlockStore {
return &mockBlockStore{config, params, nil, nil}
}
func (bs *mockBlockStore) Height() int { return len(bs.chain) }
func (bs *mockBlockStore) LoadBlock(height int) *types.Block { return bs.chain[height-1] }
func (bs *mockBlockStore) LoadBlockMeta(height int) *types.BlockMeta {
func (bs *mockBlockStore) Height() int64 { return int64(len(bs.chain)) }
func (bs *mockBlockStore) LoadBlock(height int64) *types.Block { return bs.chain[height-1] }
func (bs *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
block := bs.chain[height-1]
return &types.BlockMeta{
BlockID: types.BlockID{block.Hash(), block.MakePartSet(bs.config.GetInt("block_part_size")).Header()},
BlockID: types.BlockID{block.Hash(), block.MakePartSet(bs.params.BlockPartSizeBytes).Header()},
Header: block.Header,
}
}
func (bs *mockBlockStore) LoadBlockPart(height int, index int) *types.Part { return nil }
func (bs *mockBlockStore) LoadBlockPart(height int64, index int) *types.Part { return nil }
func (bs *mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
}
func (bs *mockBlockStore) LoadBlockCommit(height int) *types.Commit {
func (bs *mockBlockStore) LoadBlockCommit(height int64) *types.Commit {
return bs.commits[height-1]
}
func (bs *mockBlockStore) LoadSeenCommit(height int) *types.Commit {
func (bs *mockBlockStore) LoadSeenCommit(height int64) *types.Commit {
return bs.commits[height-1]
}

File diff suppressed because it is too large Load Diff

View File

@ -2,21 +2,24 @@ package consensus
import (
"bytes"
"context"
"fmt"
"testing"
"time"
. "github.com/tendermint/go-common"
"github.com/tendermint/tendermint/config/tendermint_test"
cstypes "github.com/tendermint/tendermint/consensus/types"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
tmpubsub "github.com/tendermint/tmlibs/pubsub"
)
func init() {
config = tendermint_test.ResetConfig("consensus_state_test")
config = ResetConfig("consensus_state_test")
}
func (tp *TimeoutParams) ensureProposeTimeout() time.Duration {
return time.Duration(tp.Propose0*2) * time.Millisecond
func ensureProposeTimeout(timeoutPropose int) time.Duration {
return time.Duration(timeoutPropose*2) * time.Millisecond
}
/*
@ -52,12 +55,12 @@ x * TestHalt1 - if we see +2/3 precommits after timing out into new round, we sh
//----------------------------------------------------------------------------------------------------
// ProposeSuite
func TestProposerSelection0(t *testing.T) {
func TestStateProposerSelection0(t *testing.T) {
cs1, vss := randConsensusState(4)
height, round := cs1.Height, cs1.Round
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
startTestRound(cs1, height, round)
@ -80,16 +83,16 @@ func TestProposerSelection0(t *testing.T) {
<-newRoundCh
prop = cs1.GetRoundState().Validators.GetProposer()
if !bytes.Equal(prop.Address, vss[1].Address) {
panic(Fmt("expected proposer to be validator %d. Got %X", 1, prop.Address))
if !bytes.Equal(prop.Address, vss[1].GetAddress()) {
panic(cmn.Fmt("expected proposer to be validator %d. Got %X", 1, prop.Address))
}
}
// Now let's do it all again, but starting from round 2 instead of 0
func TestProposerSelection2(t *testing.T) {
func TestStateProposerSelection2(t *testing.T) {
cs1, vss := randConsensusState(4) // test needs more work for more than 3 validators
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
// this time we jump in at round 2
incrementRound(vss[1:]...)
@ -101,8 +104,8 @@ func TestProposerSelection2(t *testing.T) {
// everyone just votes nil. we get a new proposer each round
for i := 0; i < len(vss); i++ {
prop := cs1.GetRoundState().Validators.GetProposer()
if !bytes.Equal(prop.Address, vss[(i+2)%len(vss)].Address) {
panic(Fmt("expected proposer to be validator %d. Got %X", (i+2)%len(vss), prop.Address))
if !bytes.Equal(prop.Address, vss[(i+2)%len(vss)].GetAddress()) {
panic(cmn.Fmt("expected proposer to be validator %d. Got %X", (i+2)%len(vss), prop.Address))
}
rs := cs1.GetRoundState()
@ -115,18 +118,18 @@ func TestProposerSelection2(t *testing.T) {
}
// a non-validator should timeout into the prevote round
func TestEnterProposeNoPrivValidator(t *testing.T) {
func TestStateEnterProposeNoPrivValidator(t *testing.T) {
cs, _ := randConsensusState(1)
cs.SetPrivValidator(nil)
height, round := cs.Height, cs.Round
// Listen for propose timeout event
timeoutCh := subscribeToEvent(cs.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutCh := subscribe(cs.eventBus, types.EventQueryTimeoutPropose)
startTestRound(cs, height, round)
// if we're not a validator, EnterPropose should timeout
ticker := time.NewTicker(cs.timeoutParams.ensureProposeTimeout())
ticker := time.NewTicker(ensureProposeTimeout(cs.config.TimeoutPropose))
select {
case <-timeoutCh:
case <-ticker.C:
@ -140,14 +143,14 @@ func TestEnterProposeNoPrivValidator(t *testing.T) {
}
// a validator should not timeout of the prevote round (TODO: unless the block is really big!)
func TestEnterProposeYesPrivValidator(t *testing.T) {
func TestStateEnterProposeYesPrivValidator(t *testing.T) {
cs, _ := randConsensusState(1)
height, round := cs.Height, cs.Round
// Listen for propose timeout event
timeoutCh := subscribeToEvent(cs.evsw, "tester", types.EventStringTimeoutPropose(), 1)
proposalCh := subscribeToEvent(cs.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutCh := subscribe(cs.eventBus, types.EventQueryTimeoutPropose)
proposalCh := subscribe(cs.eventBus, types.EventQueryCompleteProposal)
cs.enterNewRound(height, round)
cs.startRoutines(3)
@ -167,7 +170,7 @@ func TestEnterProposeYesPrivValidator(t *testing.T) {
}
// if we're a validator, enterPropose should not timeout
ticker := time.NewTicker(cs.timeoutParams.ensureProposeTimeout())
ticker := time.NewTicker(ensureProposeTimeout(cs.config.TimeoutPropose))
select {
case <-timeoutCh:
panic("Expected EnterPropose not to timeout")
@ -176,15 +179,15 @@ func TestEnterProposeYesPrivValidator(t *testing.T) {
}
}
func TestBadProposal(t *testing.T) {
func TestStateBadProposal(t *testing.T) {
cs1, vss := randConsensusState(2)
height, round := cs1.Height, cs1.Round
vs2 := vss[1]
partSize := config.GetInt("block_part_size")
partSize := cs1.state.ConsensusParams.BlockPartSizeBytes
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
voteCh := subscribe(cs1.eventBus, types.EventQueryVote)
propBlock, _ := cs1.createProposalBlock() //changeProposer(t, cs1, vs2)
@ -201,12 +204,14 @@ func TestBadProposal(t *testing.T) {
propBlock.AppHash = stateHash
propBlockParts := propBlock.MakePartSet(partSize)
proposal := types.NewProposal(vs2.Height, round, propBlockParts.Header(), -1, types.BlockID{})
if err := vs2.SignProposal(config.GetString("chain_id"), proposal); err != nil {
if err := vs2.SignProposal(config.ChainID(), proposal); err != nil {
t.Fatal("failed to sign bad proposal", err)
}
// set the proposal block
cs1.SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer")
if err := cs1.SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
// start the machine
startTestRound(cs1, height, round)
@ -234,13 +239,21 @@ func TestBadProposal(t *testing.T) {
// FullRoundSuite
// propose, prevote, and precommit a block
func TestFullRound1(t *testing.T) {
func TestStateFullRound1(t *testing.T) {
cs, vss := randConsensusState(1)
height, round := cs.Height, cs.Round
voteCh := subscribeToEvent(cs.evsw, "tester", types.EventStringVote(), 0)
propCh := subscribeToEvent(cs.evsw, "tester", types.EventStringCompleteProposal(), 1)
newRoundCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewRound(), 1)
// NOTE: buffer capacity of 0 ensures we can validate prevote and last commit
// before consensus can move to the next height (and cause a race condition)
cs.eventBus.Stop()
eventBus := types.NewEventBusWithBufferCapacity(0)
eventBus.SetLogger(log.TestingLogger().With("module", "events"))
cs.SetEventBus(eventBus)
eventBus.Start()
voteCh := subscribe(cs.eventBus, types.EventQueryVote)
propCh := subscribe(cs.eventBus, types.EventQueryCompleteProposal)
newRoundCh := subscribe(cs.eventBus, types.EventQueryNewRound)
startTestRound(cs, height, round)
@ -248,11 +261,9 @@ func TestFullRound1(t *testing.T) {
// grab proposal
re := <-propCh
propBlockHash := re.(types.EventDataRoundState).RoundState.(*RoundState).ProposalBlock.Hash()
propBlockHash := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState).ProposalBlock.Hash()
<-voteCh // wait for prevote
// NOTE: voteChan cap of 0 ensures we can complete this
// before consensus can move to the next height (and cause a race condition)
validatePrevote(t, cs, round, vss[0], propBlockHash)
<-voteCh // wait for precommit
@ -264,11 +275,11 @@ func TestFullRound1(t *testing.T) {
}
// nil is proposed, so prevote and precommit nil
func TestFullRoundNil(t *testing.T) {
func TestStateFullRoundNil(t *testing.T) {
cs, vss := randConsensusState(1)
height, round := cs.Height, cs.Round
voteCh := subscribeToEvent(cs.evsw, "tester", types.EventStringVote(), 1)
voteCh := subscribe(cs.eventBus, types.EventQueryVote)
cs.enterPrevote(height, round)
cs.startRoutines(4)
@ -282,13 +293,13 @@ func TestFullRoundNil(t *testing.T) {
// run through propose, prevote, precommit commit with two validators
// where the first validator has to wait for votes from the second
func TestFullRound2(t *testing.T) {
func TestStateFullRound2(t *testing.T) {
cs1, vss := randConsensusState(2)
vs2 := vss[1]
height, round := cs1.Height, cs1.Round
voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlock(), 1)
voteCh := subscribe(cs1.eventBus, types.EventQueryVote)
newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlock)
// start round and wait for propose and prevote
startTestRound(cs1, height, round)
@ -323,18 +334,18 @@ func TestFullRound2(t *testing.T) {
// two validators, 4 rounds.
// two vals take turns proposing. val1 locks on first one, precommits nil on everything else
func TestLockNoPOL(t *testing.T) {
func TestStateLockNoPOL(t *testing.T) {
cs1, vss := randConsensusState(2)
vs2 := vss[1]
height := cs1.Height
partSize := config.GetInt("block_part_size")
partSize := cs1.state.ConsensusParams.BlockPartSizeBytes
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
voteCh := subscribe(cs1.eventBus, types.EventQueryVote)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
/*
Round1 (cs1, B) // B B // B B2
@ -345,7 +356,7 @@ func TestLockNoPOL(t *testing.T) {
cs1.startRoutines(0)
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
@ -376,7 +387,7 @@ func TestLockNoPOL(t *testing.T) {
///
<-newRoundCh
log.Notice("#### ONTO ROUND 1")
t.Log("#### ONTO ROUND 1")
/*
Round2 (cs1, B) // B B2
*/
@ -385,7 +396,7 @@ func TestLockNoPOL(t *testing.T) {
// now we're on a new round and not the proposer, so wait for timeout
re = <-timeoutProposeCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
if rs.ProposalBlock != nil {
panic("Expected proposal block to be nil")
@ -398,7 +409,7 @@ func TestLockNoPOL(t *testing.T) {
validatePrevote(t, cs1, 1, vss[0], rs.LockedBlock.Hash())
// add a conflicting prevote from the other validator
signAddVotes(cs1, types.VoteTypePrevote, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2)
signAddVotes(cs1, types.VoteTypePrevote, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2)
<-voteCh
// now we're going to enter prevote again, but with invalid args
@ -413,7 +424,7 @@ func TestLockNoPOL(t *testing.T) {
// add conflicting precommit from vs2
// NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2)
signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2)
<-voteCh
// (note we're entering precommit for a second time this round, but with invalid args
@ -421,7 +432,7 @@ func TestLockNoPOL(t *testing.T) {
<-timeoutWaitCh
<-newRoundCh
log.Notice("#### ONTO ROUND 2")
t.Log("#### ONTO ROUND 2")
/*
Round3 (vs2, _) // B, B2
*/
@ -429,11 +440,11 @@ func TestLockNoPOL(t *testing.T) {
incrementRound(vs2)
re = <-proposalCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
// now we're on a new round and are the proposer
if !bytes.Equal(rs.ProposalBlock.Hash(), rs.LockedBlock.Hash()) {
panic(Fmt("Expected proposal block to be locked block. Got %v, Expected %v", rs.ProposalBlock, rs.LockedBlock))
panic(cmn.Fmt("Expected proposal block to be locked block. Got %v, Expected %v", rs.ProposalBlock, rs.LockedBlock))
}
<-voteCh // prevote
@ -462,14 +473,16 @@ func TestLockNoPOL(t *testing.T) {
incrementRound(vs2)
<-newRoundCh
log.Notice("#### ONTO ROUND 3")
t.Log("#### ONTO ROUND 3")
/*
Round4 (vs2, C) // B C // B C
*/
// now we're on a new round and not the proposer
// so set the proposal block
cs1.SetProposalAndBlock(prop, propBlock, propBlock.MakePartSet(partSize), "")
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlock.MakePartSet(partSize), ""); err != nil {
t.Fatal(err)
}
<-proposalCh
<-voteCh // prevote
@ -490,20 +503,18 @@ func TestLockNoPOL(t *testing.T) {
}
// 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
func TestLockPOLRelock(t *testing.T) {
func TestStateLockPOLRelock(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
partSize := config.GetInt("block_part_size")
partSize := cs1.state.ConsensusParams.BlockPartSizeBytes
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlockHeader(), 1)
log.Debug("vs2 last round", "lr", vs2.PrivValidator.LastRound)
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
voteCh := subscribe(cs1.eventBus, types.EventQueryVote)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlockHeader)
// everything done from perspective of cs1
@ -518,13 +529,14 @@ func TestLockPOLRelock(t *testing.T) {
<-newRoundCh
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
signAddVotes(cs1, types.VoteTypePrevote, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs2, vs3, vs4)
_, _, _ = <-voteCh, <-voteCh, <-voteCh // prevotes
// prevotes
discardFromChan(voteCh, 3)
<-voteCh // our precommit
// the proposed block should now be locked and our precommit added
@ -533,7 +545,8 @@ func TestLockPOLRelock(t *testing.T) {
// add precommits from the rest
signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs4)
signAddVotes(cs1, types.VoteTypePrecommit, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs3)
_, _, _ = <-voteCh, <-voteCh, <-voteCh // precommits
// precommites
discardFromChan(voteCh, 3)
// before we timeout to the new round set the new proposal
prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
@ -545,11 +558,13 @@ func TestLockPOLRelock(t *testing.T) {
// timeout to new round
<-timeoutWaitCh
//XXX: this isnt gauranteed to get there before the timeoutPropose ...
cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
<-newRoundCh
log.Notice("### ONTO ROUND 1")
t.Log("### ONTO ROUND 1")
/*
Round2 (vs2, C) // B C C C // C C C _)
@ -571,7 +586,8 @@ func TestLockPOLRelock(t *testing.T) {
// now lets add prevotes from everyone else for the new block
signAddVotes(cs1, types.VoteTypePrevote, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
_, _, _ = <-voteCh, <-voteCh, <-voteCh // prevotes
// prevotes
discardFromChan(voteCh, 3)
// now either we go to PrevoteWait or Precommit
select {
@ -586,12 +602,12 @@ func TestLockPOLRelock(t *testing.T) {
validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash, propBlockHash)
signAddVotes(cs1, types.VoteTypePrecommit, propBlockHash, propBlockParts.Header(), vs2, vs3)
_, _ = <-voteCh, <-voteCh
discardFromChan(voteCh, 2)
be := <-newBlockCh
b := be.(types.EventDataNewBlockHeader)
re = <-newRoundCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
if rs.Height != 2 {
panic("Expected height to increment")
}
@ -602,17 +618,17 @@ func TestLockPOLRelock(t *testing.T) {
}
// 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
func TestLockPOLUnlock(t *testing.T) {
func TestStateLockPOLUnlock(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
partSize := config.GetInt("block_part_size")
partSize := cs1.state.ConsensusParams.BlockPartSizeBytes
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
// everything done from perspective of cs1
@ -627,7 +643,7 @@ func TestLockPOLUnlock(t *testing.T) {
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
@ -653,14 +669,16 @@ func TestLockPOLUnlock(t *testing.T) {
// timeout to new round
re = <-timeoutWaitCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
lockedBlockHash := rs.LockedBlock.Hash()
//XXX: this isnt gauranteed to get there before the timeoutPropose ...
cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
<-newRoundCh
log.Notice("#### ONTO ROUND 1")
t.Log("#### ONTO ROUND 1")
/*
Round2 (vs2, C) // B nil nil nil // nil nil nil _
@ -697,23 +715,23 @@ func TestLockPOLUnlock(t *testing.T) {
// a polka at round 1 but we miss it
// then a polka at round 2 that we lock on
// then we see the polka from round 1 but shouldn't unlock
func TestLockPOLSafety1(t *testing.T) {
func TestStateLockPOLSafety1(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
partSize := config.GetInt("block_part_size")
partSize := cs1.state.ConsensusParams.BlockPartSizeBytes
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
propBlock := rs.ProposalBlock
<-voteCh // prevote
@ -732,7 +750,7 @@ func TestLockPOLSafety1(t *testing.T) {
panic("failed to update validator")
}*/
log.Warn("old prop", "hash", fmt.Sprintf("%X", propBlock.Hash()))
t.Logf("old prop hash %v", fmt.Sprintf("%X", propBlock.Hash()))
// we do see them precommit nil
signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs3, vs4)
@ -743,11 +761,13 @@ func TestLockPOLSafety1(t *testing.T) {
incrementRound(vs2, vs3, vs4)
//XXX: this isnt gauranteed to get there before the timeoutPropose ...
cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
<-newRoundCh
log.Notice("### ONTO ROUND 1")
t.Log("### ONTO ROUND 1")
/*Round2
// we timeout and prevote our lock
// a polka happened but we didn't see it!
@ -761,12 +781,12 @@ func TestLockPOLSafety1(t *testing.T) {
re = <-proposalCh
}
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
if rs.LockedBlock != nil {
panic("we should not be locked!")
}
log.Warn("new prop", "hash", fmt.Sprintf("%X", propBlockHash))
t.Logf("new prop hash %v", fmt.Sprintf("%X", propBlockHash))
// go to prevote, prevote for proposal block
<-voteCh
validatePrevote(t, cs1, 1, vss[0], propBlockHash)
@ -787,7 +807,7 @@ func TestLockPOLSafety1(t *testing.T) {
<-newRoundCh
log.Notice("### ONTO ROUND 2")
t.Log("### ONTO ROUND 2")
/*Round3
we see the polka from round 1 but we shouldn't unlock!
*/
@ -801,12 +821,12 @@ func TestLockPOLSafety1(t *testing.T) {
// we should prevote what we're locked on
validatePrevote(t, cs1, 2, vss[0], propBlockHash)
newStepCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRoundStep(), 1)
newStepCh := subscribe(cs1.eventBus, types.EventQueryNewRoundStep)
// add prevotes from the earlier round
addVotes(cs1, prevotes...)
log.Warn("Done adding prevotes!")
t.Log("Done adding prevotes!")
ensureNoNewStep(newStepCh)
}
@ -818,17 +838,17 @@ func TestLockPOLSafety1(t *testing.T) {
// What we want:
// dont see P0, lock on P1 at R1, dont unlock using P0 at R2
func TestLockPOLSafety2(t *testing.T) {
func TestStateLockPOLSafety2(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
partSize := config.GetInt("block_part_size")
partSize := cs1.state.ConsensusParams.BlockPartSizeBytes
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
// the block for R0: gets polkad but we miss it
@ -848,15 +868,17 @@ func TestLockPOLSafety2(t *testing.T) {
incrementRound(vs2, vs3, vs4)
cs1.updateRoundStep(0, RoundStepPrecommitWait)
cs1.updateRoundStep(0, cstypes.RoundStepPrecommitWait)
log.Notice("### ONTO Round 1")
t.Log("### ONTO Round 1")
// jump in at round 1
height := cs1.Height
startTestRound(cs1, height, 1)
<-newRoundCh
cs1.SetProposalAndBlock(prop1, propBlock1, propBlockParts1, "some peer")
if err := cs1.SetProposalAndBlock(prop1, propBlock1, propBlockParts1, "some peer"); err != nil {
t.Fatal(err)
}
<-proposalCh
<-voteCh // prevote
@ -878,16 +900,18 @@ func TestLockPOLSafety2(t *testing.T) {
// in round 2 we see the polkad block from round 0
newProp := types.NewProposal(height, 2, propBlockParts0.Header(), 0, propBlockID1)
if err := vs3.SignProposal(config.GetString("chain_id"), newProp); err != nil {
if err := vs3.SignProposal(config.ChainID(), newProp); err != nil {
t.Fatal(err)
}
if err := cs1.SetProposalAndBlock(newProp, propBlock0, propBlockParts0, "some peer"); err != nil {
t.Fatal(err)
}
cs1.SetProposalAndBlock(newProp, propBlock0, propBlockParts0, "some peer")
// Add the pol votes
addVotes(cs1, prevotes...)
<-newRoundCh
log.Notice("### ONTO Round 2")
t.Log("### ONTO Round 2")
/*Round2
// now we see the polka from round 1, but we shouldnt unlock
*/
@ -913,14 +937,14 @@ func TestLockPOLSafety2(t *testing.T) {
// TODO: Slashing
/*
func TestSlashingPrevotes(t *testing.T) {
func TestStateSlashingPrevotes(t *testing.T) {
cs1, vss := randConsensusState(2)
vs2 := vss[1]
proposalCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringCompleteProposal() , 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringTimeoutWait() , 1)
newRoundCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringNewRound() , 1)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
// start round and wait for propose and prevote
@ -929,7 +953,7 @@ func TestSlashingPrevotes(t *testing.T) {
re := <-proposalCh
<-voteCh // prevote
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
// we should now be stuck in limbo forever, waiting for more prevotes
// add one for a different block should cause us to go into prevote wait
@ -948,14 +972,14 @@ func TestSlashingPrevotes(t *testing.T) {
// XXX: Check for existence of Dupeout info
}
func TestSlashingPrecommits(t *testing.T) {
func TestStateSlashingPrecommits(t *testing.T) {
cs1, vss := randConsensusState(2)
vs2 := vss[1]
proposalCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringCompleteProposal() , 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringTimeoutWait() , 1)
newRoundCh := subscribeToEvent(cs1.evsw,"tester",types.EventStringNewRound() , 1)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
// start round and wait for propose and prevote
@ -993,23 +1017,23 @@ func TestSlashingPrecommits(t *testing.T) {
// 4 vals.
// we receive a final precommit after going into next round, but others might have gone to commit already!
func TestHalt1(t *testing.T) {
func TestStateHalt1(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
partSize := config.GetInt("block_part_size")
partSize := cs1.state.ConsensusParams.BlockPartSizeBytes
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlock(), 1)
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlock)
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
propBlock := rs.ProposalBlock
propBlockParts := propBlock.MakePartSet(partSize)
@ -1032,9 +1056,9 @@ func TestHalt1(t *testing.T) {
// timeout to new round
<-timeoutWaitCh
re = <-newRoundCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
log.Notice("### ONTO ROUND 1")
t.Log("### ONTO ROUND 1")
/*Round2
// we timeout and prevote our lock
// a polka happened but we didn't see it!
@ -1050,9 +1074,26 @@ func TestHalt1(t *testing.T) {
// receiving that precommit should take us straight to commit
<-newBlockCh
re = <-newRoundCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
if rs.Height != 2 {
panic("expected height to increment")
}
}
// subscribe subscribes test client to the given query and returns a channel with cap = 1.
func subscribe(eventBus *types.EventBus, q tmpubsub.Query) <-chan interface{} {
out := make(chan interface{}, 1)
err := eventBus.Subscribe(context.Background(), testSubscriber, q, out)
if err != nil {
panic(fmt.Sprintf("failed to subscribe %s to %v", testSubscriber, q))
}
return out
}
// discardFromChan reads n values from the channel.
func discardFromChan(ch <-chan interface{}, n int) {
for i := 0; i < n; i++ {
<-ch
}
}

View File

@ -1,36 +0,0 @@
# Generating test data
To generate the data, run `build.sh`. See that script for more details.
Make sure to adjust the stepChanges in the testCases if the number of messages changes.
This sometimes happens for the `small_block2.cswal`, where the number of block parts changes between 4 and 5.
If you need to change the signatures, you can use a script as follows:
The privBytes comes from `config/tendermint_test/...`:
```
package main
import (
"encoding/hex"
"fmt"
"github.com/tendermint/go-crypto"
)
func main() {
signBytes, err := hex.DecodeString("7B22636861696E5F6964223A2274656E6465726D696E745F74657374222C22766F7465223A7B22626C6F636B5F68617368223A2242453544373939433846353044354645383533364334333932464443384537423342313830373638222C22626C6F636B5F70617274735F686561646572223A506172745365747B543A31204236323237323535464632307D2C22686569676874223A312C22726F756E64223A302C2274797065223A327D7D")
if err != nil {
panic(err)
}
privBytes, err := hex.DecodeString("27F82582AEFAE7AB151CFB01C48BB6C1A0DA78F9BDDA979A9F70A84D074EB07D3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8")
if err != nil {
panic(err)
}
privKey := crypto.PrivKeyEd25519{}
copy(privKey[:], privBytes)
signature := privKey.Sign(signBytes)
fmt.Printf("Signature Bytes: %X\n", signature.Bytes())
}
```

View File

@ -1,103 +0,0 @@
#! /bin/bash
# XXX: removes tendermint dir
cd $GOPATH/src/github.com/tendermint/tendermint
# specify a dir to copy
# TODO: eventually we should replace with `tendermint init --test`
DIR=$HOME/.tendermint_test/consensus_state_test
rm -rf $HOME/.tendermint
cp -r $DIR $HOME/.tendermint
function reset(){
rm -rf $HOME/.tendermint/data
tendermint unsafe_reset_priv_validator
}
reset
# empty block
function empty_block(){
tendermint node --proxy_app=dummy &> /dev/null &
sleep 5
killall tendermint
# /q would print up to and including the match, then quit.
# /Q doesn't include the match.
# http://unix.stackexchange.com/questions/11305/grep-show-all-the-file-up-to-the-match
sed '/ENDHEIGHT: 1/Q' ~/.tendermint/data/cs.wal/wal > consensus/test_data/empty_block.cswal
reset
}
# many blocks
function many_blocks(){
bash scripts/txs/random.sh 1000 36657 &> /dev/null &
PID=$!
tendermint node --proxy_app=dummy &> /dev/null &
sleep 7
killall tendermint
kill -9 $PID
sed '/ENDHEIGHT: 6/Q' ~/.tendermint/data/cs.wal/wal > consensus/test_data/many_blocks.cswal
reset
}
# small block 1
function small_block1(){
bash scripts/txs/random.sh 1000 36657 &> /dev/null &
PID=$!
tendermint node --proxy_app=dummy &> /dev/null &
sleep 10
killall tendermint
kill -9 $PID
sed '/ENDHEIGHT: 1/Q' ~/.tendermint/data/cs.wal/wal > consensus/test_data/small_block1.cswal
reset
}
# small block 2 (part size = 512)
function small_block2(){
echo "" >> ~/.tendermint/config.toml
echo "block_part_size = 512" >> ~/.tendermint/config.toml
bash scripts/txs/random.sh 1000 36657 &> /dev/null &
PID=$!
tendermint node --proxy_app=dummy &> /dev/null &
sleep 5
killall tendermint
kill -9 $PID
sed '/ENDHEIGHT: 1/Q' ~/.tendermint/data/cs.wal/wal > consensus/test_data/small_block2.cswal
reset
}
case "$1" in
"small_block1")
small_block1
;;
"small_block2")
small_block2
;;
"empty_block")
empty_block
;;
"many_blocks")
many_blocks
;;
*)
small_block1
small_block2
empty_block
many_blocks
esac

View File

@ -1,10 +0,0 @@
#ENDHEIGHT: 0
{"time":"2016-12-18T05:05:33.502Z","msg":[3,{"duration":974084551,"height":1,"round":0,"step":1}]}
{"time":"2016-12-18T05:05:33.505Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPropose"}]}
{"time":"2016-12-18T05:05:33.505Z","msg":[2,{"msg":[17,{"Proposal":{"height":1,"round":0,"block_parts_header":{"total":1,"hash":"71D2DA2336A9F84C22A28FF6C67F35F3478FC0AF"},"pol_round":-1,"pol_block_id":{"hash":"","parts":{"total":0,"hash":""}},"signature":[1,"62C0F2BCCB491399EEDAF8E85837ADDD4E25BAB7A84BFC4F0E88594531FBC6D4755DEC7E6427F04AD7EB8BB89502762AB4380C7BBA93A4C297E6180EC78E3504"]}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:33.506Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":0,"bytes":"0101010F74656E6465726D696E745F74657374010114914148D83E0DC00000000000000114354594CBFC1A7BCA1AD0050ED6AA010023EADA390001000100000000","proof":{"aunts":[]}}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:33.508Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPrevote"}]}
{"time":"2016-12-18T05:05:33.508Z","msg":[2,{"msg":[20,{"Vote":{"validator_address":"D028C9981F7A87F3093672BF0D5B0E2A1B3ED456","validator_index":0,"height":1,"round":0,"type":1,"block_id":{"hash":"3E83DF89A01C5F104912E095F32451C202F34717","parts":{"total":1,"hash":"71D2DA2336A9F84C22A28FF6C67F35F3478FC0AF"}},"signature":[1,"B64D0BB64B2E9AAFDD4EBEA679644F77AE774D69E3E2E1B042AB15FE4F84B1427AC6C8A25AFF58EA22011AE567FEA49D2EE7354382E915AD85BF40C58FA6130C"]}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:33.509Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPrecommit"}]}
{"time":"2016-12-18T05:05:33.509Z","msg":[2,{"msg":[20,{"Vote":{"validator_address":"D028C9981F7A87F3093672BF0D5B0E2A1B3ED456","validator_index":0,"height":1,"round":0,"type":2,"block_id":{"hash":"3E83DF89A01C5F104912E095F32451C202F34717","parts":{"total":1,"hash":"71D2DA2336A9F84C22A28FF6C67F35F3478FC0AF"}},"signature":[1,"D83E968392D1BF09821E0D05079DAB5491CABD89BE128BD1CF573ED87148BA84667A56C0A069EFC90760F25EDAC62BC324DBB12EA63F44E6CB2D3500FE5E640F"]}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:33.509Z","msg":[1,{"height":1,"round":0,"step":"RoundStepCommit"}]}

File diff suppressed because one or more lines are too long

View File

@ -1,14 +0,0 @@
#ENDHEIGHT: 0
{"time":"2016-12-18T05:05:43.641Z","msg":[3,{"duration":969409681,"height":1,"round":0,"step":1}]}
{"time":"2016-12-18T05:05:43.643Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPropose"}]}
{"time":"2016-12-18T05:05:43.643Z","msg":[2,{"msg":[17,{"Proposal":{"height":1,"round":0,"block_parts_header":{"total":5,"hash":"C916905C3C444501DDDAA1BF52E959B7531E762E"},"pol_round":-1,"pol_block_id":{"hash":"","parts":{"total":0,"hash":""}},"signature":[1,"F1A8E9928889C68FD393F3983B5362AECA4A95AA13FE3C78569B2515EC046893CB718071CAF54F3F1507DCD851B37CD5557EA17BB5471D2DC6FB5AC5FBB72E02"]}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:43.643Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":0,"bytes":"0101010F74656E6465726D696E745F7465737401011491414B3483A8400190000000000114926EA77D30A4D19866159DE7E58AA9461F90F9D10114354594CBFC1A7BCA1AD0050ED6AA010023EADA3900010190010D6162636431323D646362613132010D6162636431333D646362613133010D6162636431343D646362613134010D6162636431353D646362613135010D6162636431363D646362613136010D6162636431373D646362613137010D6162636431383D646362613138010D6162636431393D646362613139010D6162636432303D646362613230010D6162636432313D646362613231010D6162636432323D646362613232010D6162636432333D646362613233010D6162636432343D646362613234010D6162636432353D646362613235010D6162636432363D646362613236010D6162636432373D646362613237010D6162636432383D646362613238010D6162636432393D646362613239010D6162636433303D646362613330010D6162636433313D646362613331010D6162636433323D646362613332010D6162636433333D646362613333010D6162636433343D646362613334010D6162636433353D646362613335010D6162636433363D646362613336010D6162636433373D646362613337010D6162636433383D646362613338010D6162636433393D646362613339010D6162636434303D","proof":{"aunts":["C9FBD66B63A976638196323F5B93494BDDFC9EED","47FD83BB7607E679EE5CF0783372D13C5A264056","FEEC97078A26B7F6057821C0660855170CC6F1D7"]}}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:43.643Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":1,"bytes":"646362613430010D6162636434313D646362613431010D6162636434323D646362613432010D6162636434333D646362613433010D6162636434343D646362613434010D6162636434353D646362613435010D6162636434363D646362613436010D6162636434373D646362613437010D6162636434383D646362613438010D6162636434393D646362613439010D6162636435303D646362613530010D6162636435313D646362613531010D6162636435323D646362613532010D6162636435333D646362613533010D6162636435343D646362613534010D6162636435353D646362613535010D6162636435363D646362613536010D6162636435373D646362613537010D6162636435383D646362613538010D6162636435393D646362613539010D6162636436303D646362613630010D6162636436313D646362613631010D6162636436323D646362613632010D6162636436333D646362613633010D6162636436343D646362613634010D6162636436353D646362613635010D6162636436363D646362613636010D6162636436373D646362613637010D6162636436383D646362613638010D6162636436393D646362613639010D6162636437303D646362613730010D6162636437313D646362613731010D6162636437323D646362613732010D6162636437333D646362613733010D6162636437343D6463","proof":{"aunts":["D7FB03B935B77C322064F8277823CDB5C7018597","47FD83BB7607E679EE5CF0783372D13C5A264056","FEEC97078A26B7F6057821C0660855170CC6F1D7"]}}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:43.644Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":2,"bytes":"62613734010D6162636437353D646362613735010D6162636437363D646362613736010D6162636437373D646362613737010D6162636437383D646362613738010D6162636437393D646362613739010D6162636438303D646362613830010D6162636438313D646362613831010D6162636438323D646362613832010D6162636438333D646362613833010D6162636438343D646362613834010D6162636438353D646362613835010D6162636438363D646362613836010D6162636438373D646362613837010D6162636438383D646362613838010D6162636438393D646362613839010D6162636439303D646362613930010D6162636439313D646362613931010D6162636439323D646362613932010D6162636439333D646362613933010D6162636439343D646362613934010D6162636439353D646362613935010D6162636439363D646362613936010D6162636439373D646362613937010D6162636439383D646362613938010D6162636439393D646362613939010F616263643130303D64636261313030010F616263643130313D64636261313031010F616263643130323D64636261313032010F616263643130333D64636261313033010F616263643130343D64636261313034010F616263643130353D64636261313035010F616263643130363D64636261313036010F616263643130373D64636261","proof":{"aunts":["A607D9BF5107E6C9FD19B6928D9CC7714B0730E4","FEEC97078A26B7F6057821C0660855170CC6F1D7"]}}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:43.644Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":3,"bytes":"313037010F616263643130383D64636261313038010F616263643130393D64636261313039010F616263643131303D64636261313130010F616263643131313D64636261313131010F616263643131323D64636261313132010F616263643131333D64636261313133010F616263643131343D64636261313134010F616263643131353D64636261313135010F616263643131363D64636261313136010F616263643131373D64636261313137010F616263643131383D64636261313138010F616263643131393D64636261313139010F616263643132303D64636261313230010F616263643132313D64636261313231010F616263643132323D64636261313232010F616263643132333D64636261313233010F616263643132343D64636261313234010F616263643132353D64636261313235010F616263643132363D64636261313236010F616263643132373D64636261313237010F616263643132383D64636261313238010F616263643132393D64636261313239010F616263643133303D64636261313330010F616263643133313D64636261313331010F616263643133323D64636261313332010F616263643133333D64636261313333010F616263643133343D64636261313334010F616263643133353D64636261313335010F616263643133363D64636261313336010F616263643133373D646362613133","proof":{"aunts":["0FD794B3506B9E92CDE3703F7189D42167E77095","86D455F542DA79F5A764B9DABDEABF01F4BAB2AB"]}}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:43.644Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":4,"bytes":"37010F616263643133383D64636261313338010F616263643133393D64636261313339010F616263643134303D64636261313430010F616263643134313D64636261313431010F616263643134323D64636261313432010F616263643134333D64636261313433010F616263643134343D64636261313434010F616263643134353D64636261313435010F616263643134363D64636261313436010F616263643134373D64636261313437010F616263643134383D64636261313438010F616263643134393D64636261313439010F616263643135303D64636261313530010F616263643135313D64636261313531010F616263643135323D64636261313532010F616263643135333D64636261313533010F616263643135343D64636261313534010F616263643135353D646362613135350100000000","proof":{"aunts":["50CBDC078A660EAE3442BA355BE10EE0D04408D1","86D455F542DA79F5A764B9DABDEABF01F4BAB2AB"]}}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:43.645Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPrevote"}]}
{"time":"2016-12-18T05:05:43.645Z","msg":[2,{"msg":[20,{"Vote":{"validator_address":"D028C9981F7A87F3093672BF0D5B0E2A1B3ED456","validator_index":0,"height":1,"round":0,"type":1,"block_id":{"hash":"6ADACDC2871C59A67337DAFD5045A982ED070C51","parts":{"total":5,"hash":"C916905C3C444501DDDAA1BF52E959B7531E762E"}},"signature":[1,"E815E0A63B7EEE7894DE2D72372A7C393434AC8ACCC46B60C628910F73351806D55A59994F08B454BFD71EDAA0CA95733CA47E37FFDAF9AAA2431A8160176E01"]}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:43.647Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPrecommit"}]}
{"time":"2016-12-18T05:05:43.647Z","msg":[2,{"msg":[20,{"Vote":{"validator_address":"D028C9981F7A87F3093672BF0D5B0E2A1B3ED456","validator_index":0,"height":1,"round":0,"type":2,"block_id":{"hash":"6ADACDC2871C59A67337DAFD5045A982ED070C51","parts":{"total":5,"hash":"C916905C3C444501DDDAA1BF52E959B7531E762E"}},"signature":[1,"9AAC3F3A118EE039EB460E9E5308D490D671C7490309BD5D62B5F392205C7E420DFDAF90F08294FF36BE8A9AA5CC203C1F2088B42D2BB8EE40A45F2BB5C54D0A"]}}],"peer_key":""}]}
{"time":"2016-12-18T05:05:43.648Z","msg":[1,{"height":1,"round":0,"step":"RoundStepCommit"}]}

View File

@ -3,7 +3,8 @@ package consensus
import (
"time"
. "github.com/tendermint/go-common"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
)
var (
@ -14,10 +15,12 @@ var (
// conditional on the height/round/step in the timeoutInfo.
// The timeoutInfo.Duration may be non-positive.
type TimeoutTicker interface {
Start() (bool, error)
Stop() bool
Start() error
Stop() error
Chan() <-chan timeoutInfo // on which to receive a timeout
ScheduleTimeout(ti timeoutInfo) // reset the timer
SetLogger(log.Logger)
}
// timeoutTicker wraps time.Timer,
@ -26,24 +29,26 @@ type TimeoutTicker interface {
// Timeouts are scheduled along the tickChan,
// and fired on the tockChan.
type timeoutTicker struct {
BaseService
cmn.BaseService
timer *time.Timer
tickChan chan timeoutInfo
tockChan chan timeoutInfo
tickChan chan timeoutInfo // for scheduling timeouts
tockChan chan timeoutInfo // for notifying about them
}
// NewTimeoutTicker returns a new TimeoutTicker.
func NewTimeoutTicker() TimeoutTicker {
tt := &timeoutTicker{
timer: time.NewTimer(0),
tickChan: make(chan timeoutInfo, tickTockBufferSize),
tockChan: make(chan timeoutInfo, tickTockBufferSize),
}
tt.BaseService = *cmn.NewBaseService(nil, "TimeoutTicker", tt)
tt.stopTimer() // don't want to fire until the first scheduled timeout
tt.BaseService = *NewBaseService(log, "TimeoutTicker", tt)
return tt
}
// OnStart implements cmn.Service. It starts the timeout routine.
func (t *timeoutTicker) OnStart() error {
go t.timeoutRoutine()
@ -51,16 +56,19 @@ func (t *timeoutTicker) OnStart() error {
return nil
}
// OnStop implements cmn.Service. It stops the timeout routine.
func (t *timeoutTicker) OnStop() {
t.BaseService.OnStop()
t.stopTimer()
}
// Chan returns a channel on which timeouts are sent.
func (t *timeoutTicker) Chan() <-chan timeoutInfo {
return t.tockChan
}
// The timeoutRoutine is alwaya available to read from tickChan (it won't block).
// ScheduleTimeout schedules a new timeout by sending on the internal tickChan.
// The timeoutRoutine is always available to read from tickChan, so this won't block.
// The scheduling may fail if the timeoutRoutine has already scheduled a timeout for a later height/round/step.
func (t *timeoutTicker) ScheduleTimeout(ti timeoutInfo) {
t.tickChan <- ti
@ -75,7 +83,7 @@ func (t *timeoutTicker) stopTimer() {
select {
case <-t.timer.C:
default:
log.Debug("Timer already stopped")
t.Logger.Debug("Timer already stopped")
}
}
}
@ -84,12 +92,12 @@ func (t *timeoutTicker) stopTimer() {
// timers are interupted and replaced by new ticks from later steps
// timeouts of 0 on the tickChan will be immediately relayed to the tockChan
func (t *timeoutTicker) timeoutRoutine() {
log.Debug("Starting timeout routine")
t.Logger.Debug("Starting timeout routine")
var ti timeoutInfo
for {
select {
case newti := <-t.tickChan:
log.Debug("Received tick", "old_ti", ti, "new_ti", newti)
t.Logger.Debug("Received tick", "old_ti", ti, "new_ti", newti)
// ignore tickers for old height/round/step
if newti.Height < ti.Height {
@ -111,15 +119,15 @@ func (t *timeoutTicker) timeoutRoutine() {
// NOTE time.Timer allows duration to be non-positive
ti = newti
t.timer.Reset(ti.Duration)
log.Debug("Scheduled timeout", "dur", ti.Duration, "height", ti.Height, "round", ti.Round, "step", ti.Step)
t.Logger.Debug("Scheduled timeout", "dur", ti.Duration, "height", ti.Height, "round", ti.Round, "step", ti.Step)
case <-t.timer.C:
log.Info("Timed out", "dur", ti.Duration, "height", ti.Height, "round", ti.Round, "step", ti.Step)
// go routine here gaurantees timeoutRoutine doesn't block.
t.Logger.Info("Timed out", "dur", ti.Duration, "height", ti.Height, "round", ti.Round, "step", ti.Step)
// go routine here guarantees timeoutRoutine doesn't block.
// Determinism comes from playback in the receiveRoutine.
// We can eliminate it by merging the timeoutRoutine into receiveRoutine
// and managing the timeouts ourselves with a millisecond ticker
go func(toi timeoutInfo) { t.tockChan <- toi }(ti)
case <-t.Quit:
case <-t.Quit():
return
}
}

View File

@ -1,11 +1,14 @@
package consensus
package types
import (
"errors"
"fmt"
"strings"
"sync"
. "github.com/tendermint/go-common"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
type RoundVoteSet struct {
@ -13,6 +16,10 @@ type RoundVoteSet struct {
Precommits *types.VoteSet
}
var (
GotVoteFromUnwantedRoundError = errors.New("Peer has sent a vote that does not match our round for more than one round")
)
/*
Keeps track of all VoteSets from round 0 to round 'round'.
@ -29,16 +36,16 @@ One for their LastCommit round, and another for the official commit round.
*/
type HeightVoteSet struct {
chainID string
height int
height int64
valSet *types.ValidatorSet
mtx sync.Mutex
round int // max tracked round
roundVoteSets map[int]RoundVoteSet // keys: [0...round]
peerCatchupRounds map[string][]int // keys: peer.Key; values: at most 2 rounds
peerCatchupRounds map[p2p.ID][]int // keys: peer.ID; values: at most 2 rounds
}
func NewHeightVoteSet(chainID string, height int, valSet *types.ValidatorSet) *HeightVoteSet {
func NewHeightVoteSet(chainID string, height int64, valSet *types.ValidatorSet) *HeightVoteSet {
hvs := &HeightVoteSet{
chainID: chainID,
}
@ -46,20 +53,20 @@ func NewHeightVoteSet(chainID string, height int, valSet *types.ValidatorSet) *H
return hvs
}
func (hvs *HeightVoteSet) Reset(height int, valSet *types.ValidatorSet) {
func (hvs *HeightVoteSet) Reset(height int64, valSet *types.ValidatorSet) {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
hvs.height = height
hvs.valSet = valSet
hvs.roundVoteSets = make(map[int]RoundVoteSet)
hvs.peerCatchupRounds = make(map[string][]int)
hvs.peerCatchupRounds = make(map[p2p.ID][]int)
hvs.addRound(0)
hvs.round = 0
}
func (hvs *HeightVoteSet) Height() int {
func (hvs *HeightVoteSet) Height() int64 {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
return hvs.height
@ -76,7 +83,7 @@ func (hvs *HeightVoteSet) SetRound(round int) {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
if hvs.round != 0 && (round < hvs.round+1) {
PanicSanity("SetRound() must increment hvs.round")
cmn.PanicSanity("SetRound() must increment hvs.round")
}
for r := hvs.round + 1; r <= round; r++ {
if _, ok := hvs.roundVoteSets[r]; ok {
@ -89,9 +96,9 @@ func (hvs *HeightVoteSet) SetRound(round int) {
func (hvs *HeightVoteSet) addRound(round int) {
if _, ok := hvs.roundVoteSets[round]; ok {
PanicSanity("addRound() for an existing round")
cmn.PanicSanity("addRound() for an existing round")
}
log.Debug("addRound(round)", "round", round)
// log.Debug("addRound(round)", "round", round)
prevotes := types.NewVoteSet(hvs.chainID, hvs.height, round, types.VoteTypePrevote, hvs.valSet)
precommits := types.NewVoteSet(hvs.chainID, hvs.height, round, types.VoteTypePrecommit, hvs.valSet)
hvs.roundVoteSets[round] = RoundVoteSet{
@ -101,8 +108,8 @@ func (hvs *HeightVoteSet) addRound(round int) {
}
// Duplicate votes return added=false, err=nil.
// By convention, peerKey is "" if origin is self.
func (hvs *HeightVoteSet) AddVote(vote *types.Vote, peerKey string) (added bool, err error) {
// By convention, peerID is "" if origin is self.
func (hvs *HeightVoteSet) AddVote(vote *types.Vote, peerID p2p.ID) (added bool, err error) {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
if !types.IsVoteTypeValid(vote.Type) {
@ -110,15 +117,13 @@ func (hvs *HeightVoteSet) AddVote(vote *types.Vote, peerKey string) (added bool,
}
voteSet := hvs.getVoteSet(vote.Round, vote.Type)
if voteSet == nil {
if rndz := hvs.peerCatchupRounds[peerKey]; len(rndz) < 2 {
if rndz := hvs.peerCatchupRounds[peerID]; len(rndz) < 2 {
hvs.addRound(vote.Round)
voteSet = hvs.getVoteSet(vote.Round, vote.Type)
hvs.peerCatchupRounds[peerKey] = append(rndz, vote.Round)
hvs.peerCatchupRounds[peerID] = append(rndz, vote.Round)
} else {
// Peer has sent a vote that does not match our round,
// for more than one round. Bad peer!
// TODO punish peer.
log.Warn("Deal with peer giving votes from unwanted rounds")
// punish peer
err = GotVoteFromUnwantedRoundError
return
}
}
@ -164,7 +169,7 @@ func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *types.VoteSet {
case types.VoteTypePrecommit:
return rvs.Precommits
default:
PanicSanity(Fmt("Unexpected vote type %X", type_))
cmn.PanicSanity(cmn.Fmt("Unexpected vote type %X", type_))
return nil
}
}
@ -194,7 +199,7 @@ func (hvs *HeightVoteSet) StringIndented(indent string) string {
voteSetString = roundVoteSet.Precommits.StringShort()
vsStrings = append(vsStrings, voteSetString)
}
return Fmt(`HeightVoteSet{H:%v R:0~%v
return cmn.Fmt(`HeightVoteSet{H:%v R:0~%v
%s %v
%s}`,
hvs.height, hvs.round,
@ -206,15 +211,15 @@ func (hvs *HeightVoteSet) StringIndented(indent string) string {
// NOTE: if there are too many peers, or too much peer churn,
// this can cause memory issues.
// TODO: implement ability to remove peers too
func (hvs *HeightVoteSet) SetPeerMaj23(round int, type_ byte, peerID string, blockID types.BlockID) {
func (hvs *HeightVoteSet) SetPeerMaj23(round int, type_ byte, peerID p2p.ID, blockID types.BlockID) error {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
if !types.IsVoteTypeValid(type_) {
return
return fmt.Errorf("SetPeerMaj23: Invalid vote type %v", type_)
}
voteSet := hvs.getVoteSet(round, type_)
if voteSet == nil {
return
return nil // something we don't know about yet
}
voteSet.SetPeerMaj23(peerID, blockID)
return voteSet.SetPeerMaj23(types.P2PID(peerID), blockID)
}

View File

@ -1,21 +1,24 @@
package consensus
package types
import (
"testing"
"time"
. "github.com/tendermint/go-common"
"github.com/tendermint/tendermint/config/tendermint_test"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
var config *cfg.Config // NOTE: must be reset for each _test.go file
func init() {
config = tendermint_test.ResetConfig("consensus_height_vote_set_test")
config = cfg.ResetTestRoot("consensus_height_vote_set_test")
}
func TestPeerCatchupRounds(t *testing.T) {
valSet, privVals := types.RandValidatorSet(10, 1)
hvs := NewHeightVoteSet(config.GetString("chain_id"), 1, valSet)
hvs := NewHeightVoteSet(config.ChainID(), 1, valSet)
vote999_0 := makeVoteHR(t, 1, 999, privVals, 0)
added, err := hvs.AddVote(vote999_0, "peer1")
@ -31,6 +34,9 @@ func TestPeerCatchupRounds(t *testing.T) {
vote1001_0 := makeVoteHR(t, 1, 1001, privVals, 0)
added, err = hvs.AddVote(vote1001_0, "peer1")
if err != GotVoteFromUnwantedRoundError {
t.Errorf("Expected GotVoteFromUnwantedRoundError, but got %v", err)
}
if added {
t.Error("Expected to *not* add vote from peer, too many catchup rounds.")
}
@ -42,20 +48,21 @@ func TestPeerCatchupRounds(t *testing.T) {
}
func makeVoteHR(t *testing.T, height, round int, privVals []*types.PrivValidator, valIndex int) *types.Vote {
func makeVoteHR(t *testing.T, height int64, round int, privVals []types.PrivValidator, valIndex int) *types.Vote {
privVal := privVals[valIndex]
vote := &types.Vote{
ValidatorAddress: privVal.Address,
ValidatorAddress: privVal.GetAddress(),
ValidatorIndex: valIndex,
Height: height,
Round: round,
Timestamp: time.Now().UTC(),
Type: types.VoteTypePrecommit,
BlockID: types.BlockID{[]byte("fakehash"), types.PartSetHeader{}},
}
chainID := config.GetString("chain_id")
chainID := config.ChainID()
err := privVal.SignVote(chainID, vote)
if err != nil {
panic(Fmt("Error signing vote: %v", err))
panic(cmn.Fmt("Error signing vote: %v", err))
return nil
}
return vote

View File

@ -0,0 +1,57 @@
package types
import (
"fmt"
"time"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
//-----------------------------------------------------------------------------
// PeerRoundState contains the known state of a peer.
// NOTE: Read-only when returned by PeerState.GetRoundState().
type PeerRoundState struct {
Height int64 // Height peer is at
Round int // Round peer is at, -1 if unknown.
Step RoundStepType // Step peer is at
StartTime time.Time // Estimated start of round 0 at this height
Proposal bool // True if peer has proposal for this round
ProposalBlockPartsHeader types.PartSetHeader //
ProposalBlockParts *cmn.BitArray //
ProposalPOLRound int // Proposal's POL round. -1 if none.
ProposalPOL *cmn.BitArray // nil until ProposalPOLMessage received.
Prevotes *cmn.BitArray // All votes peer has for this round
Precommits *cmn.BitArray // All precommits peer has for this round
LastCommitRound int // Round of commit for last height. -1 if none.
LastCommit *cmn.BitArray // All commit precommits of commit for last height.
CatchupCommitRound int // Round that we have commit for. Not necessarily unique. -1 if none.
CatchupCommit *cmn.BitArray // All commit precommits peer has for this height & CatchupCommitRound
}
// String returns a string representation of the PeerRoundState
func (prs PeerRoundState) String() string {
return prs.StringIndented("")
}
// StringIndented returns a string representation of the PeerRoundState
func (prs PeerRoundState) StringIndented(indent string) string {
return fmt.Sprintf(`PeerRoundState{
%s %v/%v/%v @%v
%s Proposal %v -> %v
%s POL %v (round %v)
%s Prevotes %v
%s Precommits %v
%s LastCommit %v (round %v)
%s Catchup %v (round %v)
%s}`,
indent, prs.Height, prs.Round, prs.Step, prs.StartTime,
indent, prs.ProposalBlockPartsHeader, prs.ProposalBlockParts,
indent, prs.ProposalPOL, prs.ProposalPOLRound,
indent, prs.Prevotes,
indent, prs.Precommits,
indent, prs.LastCommit, prs.LastCommitRound,
indent, prs.CatchupCommit, prs.CatchupCommitRound,
indent)
}

135
consensus/types/state.go Normal file
View File

@ -0,0 +1,135 @@
package types
import (
"fmt"
"time"
"github.com/tendermint/tendermint/types"
)
//-----------------------------------------------------------------------------
// RoundStepType enum type
// RoundStepType enumerates the state of the consensus state machine
type RoundStepType uint8 // These must be numeric, ordered.
const (
RoundStepNewHeight = RoundStepType(0x01) // Wait til CommitTime + timeoutCommit
RoundStepNewRound = RoundStepType(0x02) // Setup new round and go to RoundStepPropose
RoundStepPropose = RoundStepType(0x03) // Did propose, gossip proposal
RoundStepPrevote = RoundStepType(0x04) // Did prevote, gossip prevotes
RoundStepPrevoteWait = RoundStepType(0x05) // Did receive any +2/3 prevotes, start timeout
RoundStepPrecommit = RoundStepType(0x06) // Did precommit, gossip precommits
RoundStepPrecommitWait = RoundStepType(0x07) // Did receive any +2/3 precommits, start timeout
RoundStepCommit = RoundStepType(0x08) // Entered commit state machine
// NOTE: RoundStepNewHeight acts as RoundStepCommitWait.
)
// String returns a string
func (rs RoundStepType) String() string {
switch rs {
case RoundStepNewHeight:
return "RoundStepNewHeight"
case RoundStepNewRound:
return "RoundStepNewRound"
case RoundStepPropose:
return "RoundStepPropose"
case RoundStepPrevote:
return "RoundStepPrevote"
case RoundStepPrevoteWait:
return "RoundStepPrevoteWait"
case RoundStepPrecommit:
return "RoundStepPrecommit"
case RoundStepPrecommitWait:
return "RoundStepPrecommitWait"
case RoundStepCommit:
return "RoundStepCommit"
default:
return "RoundStepUnknown" // Cannot panic.
}
}
//-----------------------------------------------------------------------------
// RoundState defines the internal consensus state.
// NOTE: Not thread safe. Should only be manipulated by functions downstream
// of the cs.receiveRoutine
type RoundState struct {
Height int64 // Height we are working on
Round int
Step RoundStepType
StartTime time.Time
CommitTime time.Time // Subjective time when +2/3 precommits for Block at Round were found
Validators *types.ValidatorSet
Proposal *types.Proposal
ProposalBlock *types.Block
ProposalBlockParts *types.PartSet
LockedRound int
LockedBlock *types.Block
LockedBlockParts *types.PartSet
ValidRound int
ValidBlock *types.Block
ValidBlockParts *types.PartSet
Votes *HeightVoteSet
CommitRound int //
LastCommit *types.VoteSet // Last precommits at Height-1
LastValidators *types.ValidatorSet
}
// RoundStateEvent returns the H/R/S of the RoundState as an event.
func (rs *RoundState) RoundStateEvent() types.EventDataRoundState {
// XXX: copy the RoundState
// if we want to avoid this, we may need synchronous events after all
rs_ := *rs
edrs := types.EventDataRoundState{
Height: rs.Height,
Round: rs.Round,
Step: rs.Step.String(),
RoundState: &rs_,
}
return edrs
}
// String returns a string
func (rs *RoundState) String() string {
return rs.StringIndented("")
}
// StringIndented returns a string
func (rs *RoundState) StringIndented(indent string) string {
return fmt.Sprintf(`RoundState{
%s H:%v R:%v S:%v
%s StartTime: %v
%s CommitTime: %v
%s Validators: %v
%s Proposal: %v
%s ProposalBlock: %v %v
%s LockedRound: %v
%s LockedBlock: %v %v
%s ValidRound: %v
%s ValidBlock: %v %v
%s Votes: %v
%s LastCommit: %v
%s LastValidators:%v
%s}`,
indent, rs.Height, rs.Round, rs.Step,
indent, rs.StartTime,
indent, rs.CommitTime,
indent, rs.Validators.StringIndented(indent+" "),
indent, rs.Proposal,
indent, rs.ProposalBlockParts.StringShort(), rs.ProposalBlock.StringShort(),
indent, rs.LockedRound,
indent, rs.LockedBlockParts.StringShort(), rs.LockedBlock.StringShort(),
indent, rs.ValidRound,
indent, rs.ValidBlockParts.StringShort(), rs.ValidBlock.StringShort(),
indent, rs.Votes.StringIndented(indent+" "),
indent, rs.LastCommit.StringShort(),
indent, rs.LastValidators.StringIndented(indent+" "),
indent)
}
// StringShort returns a string
func (rs *RoundState) StringShort() string {
return fmt.Sprintf(`RoundState{H:%v R:%v S:%v ST:%v}`,
rs.Height, rs.Round, rs.Step, rs.StartTime)
}

View File

@ -1,7 +1,7 @@
package consensus
import (
. "github.com/tendermint/go-common"
cmn "github.com/tendermint/tmlibs/common"
)
// kind of arbitrary
@ -10,4 +10,4 @@ var Major = "0" //
var Minor = "2" // replay refactor
var Revision = "2" // validation -> commit
var Version = Fmt("v%s/%s.%s.%s", Spec, Major, Minor, Revision)
var Version = cmn.Fmt("v%s/%s.%s.%s", Spec, Major, Minor, Revision)

View File

@ -1,105 +1,318 @@
package consensus
import (
"encoding/binary"
"fmt"
"hash/crc32"
"io"
"path/filepath"
"time"
auto "github.com/tendermint/go-autofile"
. "github.com/tendermint/go-common"
"github.com/tendermint/go-wire"
"github.com/pkg/errors"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/types"
auto "github.com/tendermint/tmlibs/autofile"
cmn "github.com/tendermint/tmlibs/common"
)
const (
// must be greater than params.BlockGossip.BlockPartSizeBytes + a few bytes
maxMsgSizeBytes = 1024 * 1024 // 1MB
)
//--------------------------------------------------------
// types and functions for savings consensus messages
type TimedWALMessage struct {
Time time.Time `json:"time"`
Time time.Time `json:"time"` // for debugging purposes
Msg WALMessage `json:"msg"`
}
// EndHeightMessage marks the end of the given height inside WAL.
// @internal used by scripts/wal2json util.
type EndHeightMessage struct {
Height int64 `json:"height"`
}
type WALMessage interface{}
var _ = wire.RegisterInterface(
struct{ WALMessage }{},
wire.ConcreteType{types.EventDataRoundState{}, 0x01},
wire.ConcreteType{msgInfo{}, 0x02},
wire.ConcreteType{timeoutInfo{}, 0x03},
)
func RegisterWALMessages(cdc *amino.Codec) {
cdc.RegisterInterface((*WALMessage)(nil), nil)
cdc.RegisterConcrete(types.EventDataRoundState{}, "tendermint/wal/EventDataRoundState", nil)
cdc.RegisterConcrete(msgInfo{}, "tendermint/wal/MsgInfo", nil)
cdc.RegisterConcrete(timeoutInfo{}, "tendermint/wal/TimeoutInfo", nil)
cdc.RegisterConcrete(EndHeightMessage{}, "tendermint/wal/EndHeightMessage", nil)
}
//--------------------------------------------------------
// Simple write-ahead logger
// WAL is an interface for any write-ahead logger.
type WAL interface {
Save(WALMessage)
Group() *auto.Group
SearchForEndHeight(height int64, options *WALSearchOptions) (gr *auto.GroupReader, found bool, err error)
Start() error
Stop() error
Wait()
}
// Write ahead logger writes msgs to disk before they are processed.
// Can be used for crash-recovery and deterministic replay
// TODO: currently the wal is overwritten during replay catchup
// give it a mode so it's either reading or appending - must read to end to start appending again
type WAL struct {
BaseService
type baseWAL struct {
cmn.BaseService
group *auto.Group
light bool // ignore block parts
enc *WALEncoder
}
func NewWAL(walFile string, light bool) (*WAL, error) {
func NewWAL(walFile string, light bool) (*baseWAL, error) {
err := cmn.EnsureDir(filepath.Dir(walFile), 0700)
if err != nil {
return nil, errors.Wrap(err, "failed to ensure WAL directory is in place")
}
group, err := auto.OpenGroup(walFile)
if err != nil {
return nil, err
}
wal := &WAL{
wal := &baseWAL{
group: group,
light: light,
enc: NewWALEncoder(group),
}
wal.BaseService = *NewBaseService(log, "WAL", wal)
_, err = wal.Start()
return wal, err
wal.BaseService = *cmn.NewBaseService(nil, "baseWAL", wal)
return wal, nil
}
func (wal *WAL) OnStart() error {
func (wal *baseWAL) Group() *auto.Group {
return wal.group
}
func (wal *baseWAL) OnStart() error {
size, err := wal.group.Head.Size()
if err != nil {
return err
} else if size == 0 {
wal.writeEndHeight(0)
wal.Save(EndHeightMessage{0})
}
_, err = wal.group.Start()
err = wal.group.Start()
return err
}
func (wal *WAL) OnStop() {
func (wal *baseWAL) OnStop() {
wal.BaseService.OnStop()
wal.group.Stop()
}
// called in newStep and for each pass in receiveRoutine
func (wal *WAL) Save(wmsg WALMessage) {
func (wal *baseWAL) Save(msg WALMessage) {
if wal == nil {
return
}
if wal.light {
// in light mode we only write new steps, timeouts, and our own votes (no proposals, block parts)
if mi, ok := wmsg.(msgInfo); ok {
if mi.PeerKey != "" {
if mi, ok := msg.(msgInfo); ok {
if mi.PeerID != "" {
return
}
}
}
// Write the wal message
var wmsgBytes = wire.JSONBytes(TimedWALMessage{time.Now(), wmsg})
err := wal.group.WriteLine(string(wmsgBytes))
if err := wal.enc.Encode(&TimedWALMessage{time.Now(), msg}); err != nil {
cmn.PanicQ(cmn.Fmt("Error writing msg to consensus wal: %v \n\nMessage: %v", err, msg))
}
// TODO: only flush when necessary
if err := wal.group.Flush(); err != nil {
cmn.PanicQ(cmn.Fmt("Error flushing consensus wal buf to file. Error: %v \n", err))
}
}
// WALSearchOptions are optional arguments to SearchForEndHeight.
type WALSearchOptions struct {
// IgnoreDataCorruptionErrors set to true will result in skipping data corruption errors.
IgnoreDataCorruptionErrors bool
}
// SearchForEndHeight searches for the EndHeightMessage with the height and
// returns an auto.GroupReader, whenever it was found or not and an error.
// Group reader will be nil if found equals false.
//
// CONTRACT: caller must close group reader.
func (wal *baseWAL) SearchForEndHeight(height int64, options *WALSearchOptions) (gr *auto.GroupReader, found bool, err error) {
var msg *TimedWALMessage
// NOTE: starting from the last file in the group because we're usually
// searching for the last height. See replay.go
min, max := wal.group.MinIndex(), wal.group.MaxIndex()
wal.Logger.Debug("Searching for height", "height", height, "min", min, "max", max)
for index := max; index >= min; index-- {
gr, err = wal.group.NewReader(index)
if err != nil {
return nil, false, err
}
dec := NewWALDecoder(gr)
for {
msg, err = dec.Decode()
if err == io.EOF {
// check next file
break
}
if options.IgnoreDataCorruptionErrors && IsDataCorruptionError(err) {
// do nothing
} else if err != nil {
gr.Close()
return nil, false, err
}
if m, ok := msg.Msg.(EndHeightMessage); ok {
if m.Height == height { // found
wal.Logger.Debug("Found", "height", height, "index", index)
return gr, true, nil
}
}
}
gr.Close()
}
return nil, false, nil
}
///////////////////////////////////////////////////////////////////////////////
// A WALEncoder writes custom-encoded WAL messages to an output stream.
//
// Format: 4 bytes CRC sum + 4 bytes length + arbitrary-length value (go-amino encoded)
type WALEncoder struct {
wr io.Writer
}
// NewWALEncoder returns a new encoder that writes to wr.
func NewWALEncoder(wr io.Writer) *WALEncoder {
return &WALEncoder{wr}
}
// Encode writes the custom encoding of v to the stream.
func (enc *WALEncoder) Encode(v *TimedWALMessage) error {
data := cdc.MustMarshalBinaryBare(v)
crc := crc32.Checksum(data, crc32c)
length := uint32(len(data))
totalLength := 8 + int(length)
msg := make([]byte, totalLength)
binary.BigEndian.PutUint32(msg[0:4], crc)
binary.BigEndian.PutUint32(msg[4:8], length)
copy(msg[8:], data)
_, err := enc.wr.Write(msg)
return err
}
///////////////////////////////////////////////////////////////////////////////
// IsDataCorruptionError returns true if data has been corrupted inside WAL.
func IsDataCorruptionError(err error) bool {
_, ok := err.(DataCorruptionError)
return ok
}
// DataCorruptionError is an error that occures if data on disk was corrupted.
type DataCorruptionError struct {
cause error
}
func (e DataCorruptionError) Error() string {
return fmt.Sprintf("DataCorruptionError[%v]", e.cause)
}
func (e DataCorruptionError) Cause() error {
return e.cause
}
// A WALDecoder reads and decodes custom-encoded WAL messages from an input
// stream. See WALEncoder for the format used.
//
// It will also compare the checksums and make sure data size is equal to the
// length from the header. If that is not the case, error will be returned.
type WALDecoder struct {
rd io.Reader
}
// NewWALDecoder returns a new decoder that reads from rd.
func NewWALDecoder(rd io.Reader) *WALDecoder {
return &WALDecoder{rd}
}
// Decode reads the next custom-encoded value from its reader and returns it.
func (dec *WALDecoder) Decode() (*TimedWALMessage, error) {
b := make([]byte, 4)
_, err := dec.rd.Read(b)
if err == io.EOF {
return nil, err
}
if err != nil {
PanicQ(Fmt("Error writing msg to consensus wal. Error: %v \n\nMessage: %v", err, wmsg))
return nil, fmt.Errorf("failed to read checksum: %v", err)
}
// TODO: only flush when necessary
if err := wal.group.Flush(); err != nil {
PanicQ(Fmt("Error flushing consensus wal buf to file. Error: %v \n", err))
crc := binary.BigEndian.Uint32(b)
b = make([]byte, 4)
_, err = dec.rd.Read(b)
if err == io.EOF {
return nil, err
}
if err != nil {
return nil, fmt.Errorf("failed to read length: %v", err)
}
length := binary.BigEndian.Uint32(b)
if length > maxMsgSizeBytes {
return nil, DataCorruptionError{fmt.Errorf("length %d exceeded maximum possible value of %d bytes", length, maxMsgSizeBytes)}
}
data := make([]byte, length)
_, err = dec.rd.Read(data)
if err == io.EOF {
return nil, err
}
if err != nil {
return nil, fmt.Errorf("failed to read data: %v", err)
}
// check checksum before decoding data
actualCRC := crc32.Checksum(data, crc32c)
if actualCRC != crc {
return nil, DataCorruptionError{fmt.Errorf("checksums do not match: (read: %v, actual: %v)", crc, actualCRC)}
}
var res = new(TimedWALMessage) // nolint: gosimple
err = cdc.UnmarshalBinaryBare(data, res)
if err != nil {
return nil, DataCorruptionError{fmt.Errorf("failed to decode data: %v", err)}
}
return res, err
}
func (wal *WAL) writeEndHeight(height int) {
wal.group.WriteLine(Fmt("#ENDHEIGHT: %v", height))
type nilWAL struct{}
// TODO: only flush when necessary
if err := wal.group.Flush(); err != nil {
PanicQ(Fmt("Error flushing consensus wal buf to file. Error: %v \n", err))
}
func (nilWAL) Save(m WALMessage) {}
func (nilWAL) Group() *auto.Group { return nil }
func (nilWAL) SearchForEndHeight(height int64, options *WALSearchOptions) (gr *auto.GroupReader, found bool, err error) {
return nil, false, nil
}
func (nilWAL) Start() error { return nil }
func (nilWAL) Stop() error { return nil }
func (nilWAL) Wait() {}

31
consensus/wal_fuzz.go Normal file
View File

@ -0,0 +1,31 @@
// +build gofuzz
package consensus
import (
"bytes"
"io"
)
func Fuzz(data []byte) int {
dec := NewWALDecoder(bytes.NewReader(data))
for {
msg, err := dec.Decode()
if err == io.EOF {
break
}
if err != nil {
if msg != nil {
panic("msg != nil on error")
}
return 0
}
var w bytes.Buffer
enc := NewWALEncoder(&w)
err = enc.Encode(msg)
if err != nil {
panic(err)
}
}
return 1
}

201
consensus/wal_generator.go Normal file
View File

@ -0,0 +1,201 @@
package consensus
import (
"bufio"
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/pkg/errors"
"github.com/tendermint/abci/example/kvstore"
bc "github.com/tendermint/tendermint/blockchain"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
auto "github.com/tendermint/tmlibs/autofile"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
)
// WALWithNBlocks generates a consensus WAL. It does this by spining up a
// stripped down version of node (proxy app, event bus, consensus state) with a
// persistent kvstore application and special consensus wal instance
// (byteBufferWAL) and waits until numBlocks are created. Then it returns a WAL
// content.
func WALWithNBlocks(numBlocks int) (data []byte, err error) {
config := getConfig()
app := kvstore.NewPersistentKVStoreApplication(filepath.Join(config.DBDir(), "wal_generator"))
logger := log.TestingLogger().With("wal_generator", "wal_generator")
logger.Info("generating WAL (last height msg excluded)", "numBlocks", numBlocks)
/////////////////////////////////////////////////////////////////////////////
// COPY PASTE FROM node.go WITH A FEW MODIFICATIONS
// NOTE: we can't import node package because of circular dependency
privValidatorFile := config.PrivValidatorFile()
privValidator := pvm.LoadOrGenFilePV(privValidatorFile)
genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
if err != nil {
return nil, errors.Wrap(err, "failed to read genesis file")
}
stateDB := db.NewMemDB()
blockStoreDB := db.NewMemDB()
state, err := sm.MakeGenesisState(genDoc)
if err != nil {
return nil, errors.Wrap(err, "failed to make genesis state")
}
blockStore := bc.NewBlockStore(blockStoreDB)
handshaker := NewHandshaker(stateDB, state, blockStore, genDoc.AppState())
proxyApp := proxy.NewAppConns(proxy.NewLocalClientCreator(app), handshaker)
proxyApp.SetLogger(logger.With("module", "proxy"))
if err := proxyApp.Start(); err != nil {
return nil, errors.Wrap(err, "failed to start proxy app connections")
}
defer proxyApp.Stop()
eventBus := types.NewEventBus()
eventBus.SetLogger(logger.With("module", "events"))
if err := eventBus.Start(); err != nil {
return nil, errors.Wrap(err, "failed to start event bus")
}
defer eventBus.Stop()
mempool := types.MockMempool{}
evpool := types.MockEvidencePool{}
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
consensusState := NewConsensusState(config.Consensus, state.Copy(), blockExec, blockStore, mempool, evpool)
consensusState.SetLogger(logger)
consensusState.SetEventBus(eventBus)
if privValidator != nil {
consensusState.SetPrivValidator(privValidator)
}
// END OF COPY PASTE
/////////////////////////////////////////////////////////////////////////////
// set consensus wal to buffered WAL, which will write all incoming msgs to buffer
var b bytes.Buffer
wr := bufio.NewWriter(&b)
numBlocksWritten := make(chan struct{})
wal := newByteBufferWAL(logger, NewWALEncoder(wr), int64(numBlocks), numBlocksWritten)
// see wal.go#103
wal.Save(EndHeightMessage{0})
consensusState.wal = wal
if err := consensusState.Start(); err != nil {
return nil, errors.Wrap(err, "failed to start consensus state")
}
defer consensusState.Stop()
select {
case <-numBlocksWritten:
wr.Flush()
return b.Bytes(), nil
case <-time.After(1 * time.Minute):
wr.Flush()
return b.Bytes(), fmt.Errorf("waited too long for tendermint to produce %d blocks (grep logs for `wal_generator`)", numBlocks)
}
}
// f**ing long, but unique for each test
func makePathname() string {
// get path
p, err := os.Getwd()
if err != nil {
panic(err)
}
// fmt.Println(p)
sep := string(filepath.Separator)
return strings.Replace(p, sep, "_", -1)
}
func randPort() int {
// returns between base and base + spread
base, spread := 20000, 20000
return base + cmn.RandIntn(spread)
}
func makeAddrs() (string, string, string) {
start := randPort()
return fmt.Sprintf("tcp://0.0.0.0:%d", start),
fmt.Sprintf("tcp://0.0.0.0:%d", start+1),
fmt.Sprintf("tcp://0.0.0.0:%d", start+2)
}
// getConfig returns a config for test cases
func getConfig() *cfg.Config {
pathname := makePathname()
c := cfg.ResetTestRoot(fmt.Sprintf("%s_%d", pathname, cmn.RandInt()))
// and we use random ports to run in parallel
tm, rpc, grpc := makeAddrs()
c.P2P.ListenAddress = tm
c.RPC.ListenAddress = rpc
c.RPC.GRPCListenAddress = grpc
return c
}
// byteBufferWAL is a WAL which writes all msgs to a byte buffer. Writing stops
// when the heightToStop is reached. Client will be notified via
// signalWhenStopsTo channel.
type byteBufferWAL struct {
enc *WALEncoder
stopped bool
heightToStop int64
signalWhenStopsTo chan<- struct{}
logger log.Logger
}
// needed for determinism
var fixedTime, _ = time.Parse(time.RFC3339, "2017-01-02T15:04:05Z")
func newByteBufferWAL(logger log.Logger, enc *WALEncoder, nBlocks int64, signalStop chan<- struct{}) *byteBufferWAL {
return &byteBufferWAL{
enc: enc,
heightToStop: nBlocks,
signalWhenStopsTo: signalStop,
logger: logger,
}
}
// Save writes message to the internal buffer except when heightToStop is
// reached, in which case it will signal the caller via signalWhenStopsTo and
// skip writing.
func (w *byteBufferWAL) Save(m WALMessage) {
if w.stopped {
w.logger.Debug("WAL already stopped. Not writing message", "msg", m)
return
}
if endMsg, ok := m.(EndHeightMessage); ok {
w.logger.Debug("WAL write end height message", "height", endMsg.Height, "stopHeight", w.heightToStop)
if endMsg.Height == w.heightToStop {
w.logger.Debug("Stopping WAL at height", "height", endMsg.Height)
w.signalWhenStopsTo <- struct{}{}
w.stopped = true
return
}
}
w.logger.Debug("WAL Write Message", "msg", m)
err := w.enc.Encode(&TimedWALMessage{fixedTime, m})
if err != nil {
panic(fmt.Sprintf("failed to encode the msg %v", m))
}
}
func (w *byteBufferWAL) Group() *auto.Group {
panic("not implemented")
}
func (w *byteBufferWAL) SearchForEndHeight(height int64, options *WALSearchOptions) (gr *auto.GroupReader, found bool, err error) {
return nil, false, nil
}
func (w *byteBufferWAL) Start() error { return nil }
func (w *byteBufferWAL) Stop() error { return nil }
func (w *byteBufferWAL) Wait() {}

133
consensus/wal_test.go Normal file
View File

@ -0,0 +1,133 @@
package consensus
import (
"bytes"
"crypto/rand"
// "sync"
"testing"
"time"
"github.com/tendermint/tendermint/consensus/types"
tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestWALEncoderDecoder(t *testing.T) {
now := time.Now()
msgs := []TimedWALMessage{
TimedWALMessage{Time: now, Msg: EndHeightMessage{0}},
TimedWALMessage{Time: now, Msg: timeoutInfo{Duration: time.Second, Height: 1, Round: 1, Step: types.RoundStepPropose}},
}
b := new(bytes.Buffer)
for _, msg := range msgs {
b.Reset()
enc := NewWALEncoder(b)
err := enc.Encode(&msg)
require.NoError(t, err)
dec := NewWALDecoder(b)
decoded, err := dec.Decode()
require.NoError(t, err)
assert.Equal(t, msg.Time.UTC(), decoded.Time)
assert.Equal(t, msg.Msg, decoded.Msg)
}
}
func TestWALSearchForEndHeight(t *testing.T) {
walBody, err := WALWithNBlocks(6)
if err != nil {
t.Fatal(err)
}
walFile := tempWALWithData(walBody)
wal, err := NewWAL(walFile, false)
if err != nil {
t.Fatal(err)
}
h := int64(3)
gr, found, err := wal.SearchForEndHeight(h, &WALSearchOptions{})
assert.NoError(t, err, cmn.Fmt("expected not to err on height %d", h))
assert.True(t, found, cmn.Fmt("expected to find end height for %d", h))
assert.NotNil(t, gr, "expected group not to be nil")
defer gr.Close()
dec := NewWALDecoder(gr)
msg, err := dec.Decode()
assert.NoError(t, err, "expected to decode a message")
rs, ok := msg.Msg.(tmtypes.EventDataRoundState)
assert.True(t, ok, "expected message of type EventDataRoundState")
assert.Equal(t, rs.Height, h+1, cmn.Fmt("wrong height"))
}
/*
var initOnce sync.Once
func registerInterfacesOnce() {
initOnce.Do(func() {
var _ = wire.RegisterInterface(
struct{ WALMessage }{},
wire.ConcreteType{[]byte{}, 0x10},
)
})
}
*/
func nBytes(n int) []byte {
buf := make([]byte, n)
n, _ = rand.Read(buf)
return buf[:n]
}
func benchmarkWalDecode(b *testing.B, n int) {
// registerInterfacesOnce()
buf := new(bytes.Buffer)
enc := NewWALEncoder(buf)
data := nBytes(n)
enc.Encode(&TimedWALMessage{Msg: data, Time: time.Now().Round(time.Second)})
encoded := buf.Bytes()
b.ResetTimer()
for i := 0; i < b.N; i++ {
buf.Reset()
buf.Write(encoded)
dec := NewWALDecoder(buf)
if _, err := dec.Decode(); err != nil {
b.Fatal(err)
}
}
b.ReportAllocs()
}
func BenchmarkWalDecode512B(b *testing.B) {
benchmarkWalDecode(b, 512)
}
func BenchmarkWalDecode10KB(b *testing.B) {
benchmarkWalDecode(b, 10*1024)
}
func BenchmarkWalDecode100KB(b *testing.B) {
benchmarkWalDecode(b, 100*1024)
}
func BenchmarkWalDecode1MB(b *testing.B) {
benchmarkWalDecode(b, 1024*1024)
}
func BenchmarkWalDecode10MB(b *testing.B) {
benchmarkWalDecode(b, 10*1024*1024)
}
func BenchmarkWalDecode100MB(b *testing.B) {
benchmarkWalDecode(b, 100*1024*1024)
}
func BenchmarkWalDecode1GB(b *testing.B) {
benchmarkWalDecode(b, 1024*1024*1024)
}

14
consensus/wire.go Normal file
View File

@ -0,0 +1,14 @@
package consensus
import (
amino "github.com/tendermint/go-amino"
"github.com/tendermint/go-crypto"
)
var cdc = amino.NewCodec()
func init() {
RegisterConsensusMessages(cdc)
RegisterWALMessages(cdc)
crypto.RegisterAmino(cdc)
}

68
docker-compose.yml Normal file
View File

@ -0,0 +1,68 @@
version: '3'
services:
node0:
container_name: node0
image: "tendermint/localnode"
ports:
- "46656-46657:46656-46657"
environment:
- ID=0
- LOG=${LOG:-tendermint.log}
volumes:
- ${FOLDER:-./build}:/tendermint:Z
networks:
localnet:
ipv4_address: 192.167.10.2
node1:
container_name: node1
image: "tendermint/localnode"
ports:
- "46659-46660:46656-46657"
environment:
- ID=1
- LOG=${LOG:-tendermint.log}
volumes:
- ${FOLDER:-./build}:/tendermint:Z
networks:
localnet:
ipv4_address: 192.167.10.3
node2:
container_name: node2
image: "tendermint/localnode"
environment:
- ID=2
- LOG=${LOG:-tendermint.log}
ports:
- "46661-46662:46656-46657"
volumes:
- ${FOLDER:-./build}:/tendermint:Z
networks:
localnet:
ipv4_address: 192.167.10.4
node3:
container_name: node3
image: "tendermint/localnode"
environment:
- ID=3
- LOG=${LOG:-tendermint.log}
ports:
- "46663-46664:46656-46657"
volumes:
- ${FOLDER:-./build}:/tendermint:Z
networks:
localnet:
ipv4_address: 192.167.10.5
networks:
localnet:
driver: bridge
ipam:
driver: default
config:
-
subnet: 192.167.10.0/16

7
docker-compose/Makefile Normal file
View File

@ -0,0 +1,7 @@
# Makefile for the "localnode" docker image.
all:
docker build --tag tendermint/localnode localnode
.PHONY: all

40
docker-compose/README.rst Normal file
View File

@ -0,0 +1,40 @@
localnode
=========
It is assumed that you have already `setup docker <https://docs.docker.com/engine/installation/>`__.
Description
-----------
Image for local testnets.
Add the tendermint binary to the image by attaching it in a folder to the `/tendermint` mount point.
It assumes that the configuration was created by the `tendermint testnet` command and it is also attached to the `/tendermint` mount point.
Example:
This example builds a linux tendermint binary under the `build/` folder, creates tendermint configuration for a single-node validator and runs the node:
```
cd $GOPATH/src/github.com/tendermint/tendermint
#Build binary
make build-linux
#Create configuration
docker run -e LOG="stdout" -v `pwd`/build:/tendermint tendermint/localnode testnet --o . --v 1
#Run the node
docker run -v `pwd`/build:/tendermint tendermint/localnode
```
Logging
-------
Log is saved under the attached volume, in the `tendermint.log` file. If the `LOG` environment variable is set to `stdout` at start, the log is not saved, but printed on the screen.
Special binaries
----------------
If you have multiple binaries with different names, you can specify which one to run with the BINARY environment variable. The path of the binary is relative to the attached volume.
docker-compose.yml
==================
This file creates a 4-node network using the localnode image. The nodes of the network are exposed to the host machine on ports 46656-46657, 46659-46660, 46661-46662, 46663-46664 respectively.

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