Compare commits

...

1577 Commits

Author SHA1 Message Date
Ethan Buchman
46369a1ab7 Merge pull request #1779 from tendermint/release/v0.21.0
Release/v0.21.0
2018-06-21 12:44:31 -07:00
Ethan Buchman
1e3951c61c update changelog 2018-06-21 12:47:29 -07:00
Ethan Buchman
d220a1ef13 changelog 2018-06-20 00:22:07 -07:00
Ethan Buchman
c6c468c341 update changelog 2018-06-20 00:13:23 -07:00
Ethan Buchman
1d86270e20 version 2018-06-20 00:09:55 -07:00
Ethan Buchman
43745c83db Merge branch 'release/v0.20.1' into develop 2018-06-20 00:08:51 -07:00
Ethan Buchman
c793a72ac5 Merge pull request #1769 from tendermint/1755-possible-memory-leak
Memory leak in Websocket
2018-06-19 23:57:29 -07:00
Anton Kaliaev
cfff83fa3d update changelog 2018-06-19 20:20:30 +04:00
Anton Kaliaev
4fc06e9d2a [libs/pubsub] fix memory leak
Refs #1755

I started with writing a test for wsConnection (WebsocketManager) where
I:

- create a WS connection
- do a simple echo call
- close it

No leaking goroutines, nor any leaking memory were detected.

For useful shortcuts see my blog post
https://blog.cosmos.network/debugging-the-memory-leak-in-tendermint-210186711420

Then I went to the rpc tests to see if calling Subscribe results in
memory growth. It did.

I used a slightly modified version of TestHeaderEvents function:

```
func TestHeaderEvents(t *testing.T) {
	// memory heap before
	f, err := os.Create("/tmp/mem1.mprof")
	if err != nil {
		t.Fatal(err)
	}
	pprof.WriteHeapProfile(f)
	f.Close()

	for i := 0; i < 100; i++ {
		c := getHTTPClient()
		err = c.Start()
		require.Nil(t, err)

		evtTyp := types.EventNewBlockHeader
		evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
		require.Nil(t, err)
		_, ok := evt.(types.EventDataNewBlockHeader)
		require.True(t, ok)

		c.Stop()
		c = nil
	}

	runtime.GC()

	// memory heap before
	f, err = os.Create("/tmp/mem2.mprof")
	if err != nil {
		t.Fatal(err)
	}
	pprof.WriteHeapProfile(f)
	f.Close()

	// dump all running goroutines
	time.Sleep(10 * time.Second)
	pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
}
```

```
Showing nodes accounting for 35159.16kB, 100% of 35159.16kB total
Showing top 10 nodes out of 48
      flat  flat%   sum%        cum   cum%
32022.23kB 91.08% 91.08% 32022.23kB 91.08%  github.com/tendermint/tendermint/libs/pubsub/query.(*QueryParser).Init
 1056.33kB  3.00% 94.08%  1056.33kB  3.00%  bufio.NewReaderSize
  528.17kB  1.50% 95.58%   528.17kB  1.50%  bufio.NewWriterSize
  528.17kB  1.50% 97.09%   528.17kB  1.50%  github.com/tendermint/tendermint/consensus.NewConsensusState
  512.19kB  1.46% 98.54%   512.19kB  1.46%  runtime.malg
  512.08kB  1.46%   100%   512.08kB  1.46%  syscall.ByteSliceFromString
         0     0%   100%   512.08kB  1.46%  github.com/tendermint/tendermint/consensus.(*ConsensusState).(github.com/tendermint/tendermint/consensus.defaultDecideProposal)-fm
         0     0%   100%   512.08kB  1.46%  github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote
         0     0%   100%   512.08kB  1.46%  github.com/tendermint/tendermint/consensus.(*ConsensusState).defaultDecideProposal
         0     0%   100%   512.08kB  1.46%  github.com/tendermint/tendermint/consensus.(*ConsensusState).enterNewRound
```

100 subscriptions produce 32MB.

Again, no additional goroutines are running after the end of the test
(wsConnection readRoutine and writeRoutine both finishes). **It means
that some exiting goroutine or object is holding a reference to the
*Query objects, which are leaking.**

One of them is pubsub#loop. It's using state.queries to map queries to
clients and state.clients to map clients to queries.

Before this commit, we're not thoroughly cleaning state.queries, which
was the reason for memory leakage.
2018-06-19 19:59:21 +04:00
Anton Kaliaev
aaddf5d32f set pubsub default capacity to 0
Refs #951

Jae: I don't know a good way to catch these errors in general, but
forcing pubsub's internal channel to have a capacity of 0 will reveal
bugs sooner, if the subscriber also has a 0 or small capacity ch to pull
from.
2018-06-19 17:07:21 +04:00
Anton Kaliaev
26b2e808f7 [rpc/lib/server] wrote a basic test for WebsocketManager 2018-06-19 17:06:48 +04:00
Anton Kaliaev
3d30a42943 add config to issue template 2018-06-19 11:59:14 +04:00
Anton Kaliaev
4f5492c831 add nopTxCache (Nil Object Pattern)
to better handle zero cache size
2018-06-19 11:59:07 +04:00
Anton Kaliaev
70d973016e output msg only once during start 2018-06-19 11:40:40 +04:00
Ethan Buchman
4b2348f697 mempool: fix cache_size==0. closes #1761 2018-06-18 18:21:19 -07:00
Ethan Buchman
6a324764ac fix circle 2018-06-18 17:18:35 -07:00
Ethan Buchman
3470e5d7b3 changelog and version 2018-06-18 17:15:41 -07:00
Ethan Buchman
a519825bf8 consensus: fixes #1754
* updateToState exits early if the state isn't new, which happens after
* fast syncing. This results in not sending a NewRoundStep message. The mempool
* reactor depends on PeerState, which is updated by NewRoundStep
* messages. If the peer never sends a NewRoundStep, the mempool reactor
* will think they're behind, and never forward transactions. Note this
* only happens when `create_empty_blocks = false`, because otherwise
* peers will move through the consensus state and send a NewRoundStep
* for a new step soon anyways. Simple fix is just to send the
* NewRoundStep message during updateToState even if exit early
2018-06-18 17:08:09 -07:00
Ethan Buchman
d457887dd6 Merge pull request #1759 from tendermint/bucky/readme
update README
2018-06-16 22:56:35 -07:00
Ethan Buchman
adb6a94f18 contact us at riot 2018-06-16 23:05:24 -07:00
Ethan Buchman
b8bfc041d3 update README 2018-06-16 19:00:42 -07:00
Ethan Buchman
9bad770f21 Merge pull request #1757 from tendermint/bucky/update-spec
docs/spec: some organizational cleanup
2018-06-16 13:03:00 -07:00
Ethan Buchman
d3b53e62a5 fix circle 2018-06-15 23:46:43 -07:00
Ethan Buchman
506cf6c9c7 docs/spec: DuplicateVoteEvidence 2018-06-15 23:19:42 -07:00
Ethan Buchman
b8f340afd0 docs/spec: some organizational cleanup 2018-06-15 22:56:26 -07:00
Ethan Buchman
c84be3b8dd Merge pull request #1751 from tendermint/bucky/codeowner-alex
add xla as codeowner
2018-06-14 20:22:04 -07:00
Ethan Buchman
050636d5ce add xla as codeowner 2018-06-14 17:04:45 -07:00
ia
b5775b56c6 all: gofmt (#1743)
* all: gofmt

Run 'gofmt -w .' from project root.

* Update changelog to say that I ran gofmt

* Revert "Update changelog to say that I ran gofmt"

This reverts commit 956f133ff0354fd7338e7df7c823e6f98b655da6.
2018-06-15 02:03:50 +02:00
Alexander Simmerl
19af3e9733 Merge pull request #1738 from tendermint/zarko/add-blockchain-reactor-algorithm-spec
Add algorithm for Blockchain Reactor
2018-06-15 01:47:36 +02:00
Ethan Buchman
917bf4d428 Merge pull request #1732 from maxim-levy/patch-2
typo fix
2018-06-13 17:42:29 -07:00
Anton Kaliaev
696e8c6f9e [docs] write about addr_book_strict in production notes (#1741)
Refs #1736
2018-06-13 18:24:12 +04:00
Zarko Milosevic
ce73884857 Add spec for Blockchain Reactor algorithm 2018-06-13 14:05:17 +02:00
Alexander Simmerl
fa32dc5181 Merge pull request #1739 from tendermint/dev/bump_version
Bump abci version
2018-06-13 01:48:13 +02:00
ValarDragon
ec0c901bec Bump abci version 2018-06-12 16:30:24 -07:00
Dev Ojha
b84f788f36 Switch ports 466xx to 266xx (#1735)
* Switch ports 466xx to be 266xx
This is done so the default ports aren't in the linux kernel's default ephemeral port range.

* Update ABCI import

* Bump cache on circleci

* Get more verbose output for debugging

* Bump abci dependency

* Fix accidental change of a block header's hash

* pin abci release
2018-06-12 13:25:52 +04:00
Adrian Brink
ac80b93b60 unsafe_reset_all also resets addrbook.json (#1731)
* `unsafe_reset_all` also resets addrbook.json

When executing `unsafe_reset_all` it also clear all IP addresses from
addrbook.json. This is the expected behaviour of `unsafe_reset_all`.

* Fix tests

* improve logging statements

* use correct file
2018-06-12 12:55:10 +04:00
Alexander Simmerl
dfc5aefd5f Merge pull request #1726 from tendermint/1717-panic-in-netaddress
return an error if we fail to parse external IP
2018-06-12 01:08:16 +02:00
Alexander Simmerl
eb4a8e0e7a Merge pull request #1719 from Slamper/develop
Escape paths in config template
2018-06-12 01:06:22 +02:00
Max Levy
708ddb30f7 typo fix
And typo fix
2018-06-11 22:53:48 +09:00
Anton Kaliaev
cd3a240c9f return an error if we fail to parse external IP
```
I[06-08|11:51:57.234] Getting UPNP external address                module=p2p
I[06-08|11:51:58.867] Got UPNP external address                    module=p2p address=
```

Fixes #1717

```
I[06-08|11:51:56.952] Starting multiAppConn                        module=proxy impl=multiAppConn
I[06-08|11:51:56.952] Starting localClient                         module=abci-client connection=query impl=localClient
I[06-08|11:51:56.952] Starting localClient                         module=abci-client connection=mempool impl=localClient
I[06-08|11:51:56.952] Starting localClient                         module=abci-client connection=consensus impl=localClient
I[06-08|11:51:56.952] ABCI Handshake                               module=consensus appHeight=0 appHash=
I[06-08|11:51:56.952] ABCI Replay Blocks                           module=consensus appHeight=0 storeHeight=0 stateHeight=0
I[06-08|11:51:57.053] Completed ABCI Handshake - Tendermint and App are synced module=consensus appHeight=0 appHash=
I[06-08|11:51:57.053] This node is a validator                     module=consensus addr=6816B5D9BAC32A3CDF07884D9D3D2650694C371D pubKey=PubKeyEd25519{27A40CD032DD2467342D0CF27C5EC92052D966FEC714B6CF2F3BF3146AFD0D51}
I[06-08|11:51:57.234] Starting Node                                module=main impl=Node
I[06-08|11:51:57.234] Starting EventBus                            module=events impl=EventBus
I[06-08|11:51:57.234] Local listener                               module=p2p ip=:: port=46656
I[06-08|11:51:57.234] Getting UPNP external address                module=p2p
I[06-08|11:51:58.867] Got UPNP external address                    module=p2p address=
I[06-08|11:51:58.867] Starting DefaultListener                     module=p2p impl=Listener(@<nil>:46656)
I[06-08|11:51:58.867] P2P Node ID                                  module=main ID=3629b516392e494ae717ac4c6a1ea7eb0fe421c3 file=/home/tpb/.tendermint/config/node_key.json
I[06-08|11:51:58.868] Add our address to book                      module=p2p book=/home/tpb/.tendermint/config/addrbook.json addr=null
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x38 pc=0x89fb86]

goroutine 1 [running]:
github.com/tendermint/tendermint/p2p.(*NetAddress).String(0x0, 0xc96e24, 0x17)
	/home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/netaddress.go:171 +0x26
github.com/tendermint/tendermint/p2p/pex.(*addrBook).AddOurAddress(0xc420190620, 0x0)
	/home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/pex/addrbook.go:160 +0x116
github.com/tendermint/tendermint/node.(*Node).OnStart(0xc420286d00, 0xc4201b8010, 0xd)
	/home/tpb/code/go/src/github.com/tendermint/tendermint/node/node.go:402 +0x547
github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start(0xc420286d00, 0xe51c40, 0xc42000bd40)
	/home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x3bd
github.com/tendermint/tendermint/cmd/tendermint/commands.NewRunNodeCmd.func1(0xc42022e000, 0xc4200acdc0, 0x0, 0x1, 0x0, 0x0)
	/home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/commands/run_node.go:58 +0xfe
github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).execute(0xc42022e000, 0xc4200acda0, 0x1, 0x1, 0xc42022e000, 0xc4200acda0)
	/home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:762 +0x468
github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0x1289280, 0xbbdda0, 0xc420015e01, 0xc4201bc640)
	/home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:852 +0x30a
github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).Execute(0x1289280, 0xc4201bc640, 0xc420015e98)
	/home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:800 +0x2b
github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli.Executor.Execute(0x1289280, 0xde5798, 0x2, 0xc4200332c0)
	/home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli/setup.go:89 +0x4e
main.main()
	/home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/main.go:45 +0x24d
```
2018-06-09 15:03:38 +04:00
Hendrik Hofstadt
e93865f7de escape paths in config template 2018-06-08 20:44:54 -07:00
Alexander Simmerl
2e0466d1c8 Merge pull request #1722 from tendermint/dev/document_peer_types
Update description of seed and persistent peer nodes
2018-06-09 02:14:48 +02:00
ValarDragon
fd9375c35b Docs: Update description of seeds and persistent peers 2018-06-09 01:25:46 +02:00
Ethan Buchman
5ebf9b816b Merge pull request #1698 from tendermint/zach/rst-2-md
docs to markdown
2018-06-07 21:46:18 -07:00
Zach Ramsay
724b6c39b8 style fixes/typos/etc from PR review 2018-06-07 10:01:31 -04:00
Zach Ramsay
9aef3fa610 docs: pretty fixes 2018-06-07 09:41:57 -04:00
Zach Ramsay
e82ab1c374 moar fixes 2018-06-07 09:41:57 -04:00
Zach Ramsay
ffa8b5f620 oomph 2018-06-07 09:41:57 -04:00
Zach Ramsay
df07f8b36a moar 2018-06-07 09:41:57 -04:00
Zach Ramsay
d4d91d7781 running in prod 2018-06-07 09:41:57 -04:00
Zach Ramsay
3039aa1e67 intro 2018-06-07 09:41:57 -04:00
Zach Ramsay
d4d79886b2 indexing txns 2018-06-07 09:41:57 -04:00
Zach Ramsay
b429d65f9f how to read logs 2018-06-07 09:41:57 -04:00
Zach Ramsay
20e1eadcf1 getting started 2018-06-07 09:41:57 -04:00
Zach Ramsay
2e18a4e633 determinism & ecosystem 2018-06-07 09:41:57 -04:00
Zach Ramsay
b860018975 deploy tesnets 2018-06-07 09:41:57 -04:00
Zach Ramsay
44c88805a7 app devel 2018-06-07 09:41:57 -04:00
Zach Ramsay
a9b6fcdbc4 docs: cleanup/clarify build process 2018-06-07 09:41:57 -04:00
Zach Ramsay
14a5dfd945 docs: start move back to md 2018-06-07 09:41:57 -04:00
Ethan Buchman
24fa2a62b0 dev version bump 2018-06-06 20:57:19 -07:00
Ethan Buchman
27bd1deabe Merge pull request #1703 from tendermint/release/v0.20.0
Release/v0.20.0
2018-06-06 20:47:17 -07:00
Ethan Buchman
76c82fd433 add more tests 2018-06-06 20:49:00 -07:00
Ethan Buchman
9481cabd50 fixes from review 2018-06-06 20:45:20 -07:00
Ethan Buchman
46b957929c Merge branch 'develop' into release/v0.20.0 2018-06-06 19:24:36 -07:00
Ethan Buchman
512e563d4b Merge pull request #1694 from tendermint/dev/bsd_install_script
docs: Add BSD install script
2018-06-06 19:14:46 -07:00
ValarDragon
a6a4fc7784 docs: Add BSD install script 2018-06-06 17:57:25 -07:00
Ethan Buchman
bfcec02423 Merge pull request #1702 from tendermint/xla/fix-racy-config
Fix race when mutating MConnConfig
2018-06-06 17:15:53 -07:00
Ethan Buchman
fcf61b8088 check addrs match pubkeys in abci Validator. version bump 2018-06-06 16:35:35 -07:00
Ethan Buchman
46fb179605 Merge pull request #1701 from tendermint/bucky/abci-fixes
Bucky/abci fixes
2018-06-06 16:12:12 -07:00
Ethan Buchman
89925501f3 p2p/filter/pubkey -> p2p/filter/id 2018-06-06 16:13:51 -07:00
Ethan Buchman
6b8613b3e7 ResponseEndBlock: ensure Address matches PubKey if provided 2018-06-06 16:12:14 -07:00
Ethan Buchman
8be27494bb update abci spec. add address spec 2018-06-06 16:11:58 -07:00
Alexander Simmerl
c661a3ec21 Fix race when mutating MConnConfig
Instead of mutating the passed in MConnConfig part of P2PConfig we just
use the default and override the values, the same as before as it was
always the default version. This is yet another good reason to not embed
information and access to config structs in our components and will go
away with the ongoing refactoring in #1325.
2018-06-07 01:09:13 +02:00
Ethan Buchman
8e45348737 update for abci v0.11.0 release. let InitChain update validators 2018-06-06 15:47:04 -07:00
Ethan Buchman
7dfc74a6b6 Merge pull request #1667 from tendermint/bucky/abci-11
Update ABCI for new PubKey type and changes to BeginBlock and InitChain
2018-06-06 13:16:09 -07:00
Ethan Buchman
2edc68c59b use all fields in abci types 2018-06-06 13:07:17 -07:00
Dev Ojha
fe4123684d Change reset messages (#1699) 2018-06-06 22:07:10 +04:00
Ethan Buchman
2897685c57 abci header takes ValidatorsHash 2018-06-06 00:28:12 -07:00
Ethan Buchman
71556c62eb fixes from rebase 2018-06-05 22:14:37 -07:00
Ethan Buchman
54e61468d4 fixes from review 2018-06-05 22:04:38 -07:00
Ethan Buchman
5c7ccbd4a7 use const for abci type strings 2018-06-05 22:04:38 -07:00
Ethan Buchman
e2f5a6fbe4 update abci 2018-06-05 22:04:38 -07:00
Ethan Buchman
aa8be33da1 fix fmt 2018-06-05 22:04:27 -07:00
Ethan Buchman
909f66e841 remove extra eventBus 2018-06-05 22:04:27 -07:00
Ethan Buchman
3d2c4fd309 update Evidence type - requires pubkey and valset to verify and convert to abci.Evidence 2018-06-05 22:04:26 -07:00
Ethan Buchman
e5bca1df6f update godep for abci 2018-06-05 22:00:43 -07:00
Ethan Buchman
866bcceb35 fix consensus tests 2018-06-05 22:00:25 -07:00
Ethan Buchman
e1e6878a4d fix state tests 2018-06-05 22:00:25 -07:00
Ethan Buchman
e4147b6f1a state test runs 2018-06-05 22:00:25 -07:00
Ethan Buchman
7606b7595f compiles 2018-06-05 22:00:25 -07:00
Ethan Buchman
485b4a0c6f revert gogo 2018-06-05 21:59:52 -07:00
Ethan Buchman
575d94dbb9 state compiles 2018-06-05 21:59:52 -07:00
Ethan Buchman
ebd2fe7a68 more types 2018-06-05 21:59:52 -07:00
Ethan Buchman
f28eae7816 update types 2018-06-05 21:59:52 -07:00
Ethan Buchman
e13c1ab735 update for new abci 2018-06-05 21:59:52 -07:00
Ethan Buchman
0e0461d9bc dev version bump 2018-06-05 18:54:30 -07:00
Ethan Buchman
057e076ca9 Merge pull request #1693 from tendermint/release/v0.19.9
Release/v0.19.9
2018-06-05 18:00:02 -07:00
Ethan Buchman
775fef31c2 remove go-wire from test/app/grpc_client 2018-06-05 17:43:39 -07:00
Ethan Buchman
9cb079dcc6 dep, version, changelog 2018-06-05 17:38:54 -07:00
Ethan Buchman
67180344b7 Merge pull request #1663 from tendermint/zach/quick-install
quick install script
2018-06-05 17:17:47 -07:00
Ethan Buchman
825fdf2c24 Merge pull request #1679 from tendermint/flush-wal-on-stop
Flush cs.wal on stop
2018-06-05 17:14:19 -07:00
Ethan Buchman
61002ad264 Merge pull request #1628 from tendermint/bucky/selective-evidence-broadcast
evidence: dont send evidence to unsynced peers
2018-06-05 17:07:29 -07:00
Ethan Buchman
41e847ec97 linter 2018-06-05 17:02:05 -07:00
Ethan Buchman
55bae62d71 fix test 2018-06-05 16:54:58 -07:00
Ethan Buchman
d2259696af Merge pull request #1689 from tendermint/1688-tx-search-panic
validate per_page before page
2018-06-05 07:52:49 -07:00
Ethan Buchman
32719123d9 Merge pull request #1687 from tendermint/sdk-1045-memory-leak
do not drain the channel because there is no channel, duh
2018-06-05 07:51:21 -07:00
Anton Kaliaev
2ce8179c8b validate per_page before page
plus an additional check just in case
Closes #1688
2018-06-05 16:20:48 +04:00
Anton Kaliaev
b8c076ca79 do not drain the channel because there is no channel, duh
Fixes https://github.com/cosmos/cosmos-sdk/issues/1045
2018-06-05 14:57:20 +04:00
Ethan Buchman
1b2e34738a checkSendEvidenceMessage 2018-06-05 00:01:01 -07:00
Ethan Buchman
566024b64f use Hash as map key 2018-06-04 21:50:29 -07:00
Ethan Buchman
932381effa evidence: give each peer a go-routine 2018-06-04 21:20:23 -07:00
Ethan Buchman
2007c66091 fix test 2018-06-04 21:20:23 -07:00
Ethan Buchman
97c5533c35 update some comments 2018-06-04 21:20:23 -07:00
Ethan Buchman
3d33226e80 move types/services.go to state pkg. pass State to evpool.Update 2018-06-04 21:20:23 -07:00
Ethan Buchman
edb851280a state: b -> block 2018-06-04 21:20:23 -07:00
Ethan Buchman
dd62f06994 state: s -> state 2018-06-04 21:20:23 -07:00
Ethan Buchman
19d95b5410 evidence: check peerstate exists; dont send old evidence 2018-06-04 21:20:23 -07:00
Ethan Buchman
53937a8129 changelog 2018-06-04 21:20:23 -07:00
Ethan Buchman
f1c53c7358 evidence: dont send evidence to unsynced peers
* only send evidence to peers that are synced enough to validate it all
* closes #1624
2018-06-04 21:20:23 -07:00
Ethan Buchman
3445f1206e Merge pull request #1683 from tendermint/bucky/test
fix byz-test
2018-06-04 21:09:10 -07:00
Ethan Buchman
097f778c1e fix byz-test 2018-06-04 20:48:35 -07:00
Ethan Buchman
c85c21d1bc Merge pull request #1670 from tendermint/xla/extract-privval
Extract priv_validator into first class package
2018-06-04 18:57:09 -07:00
Ethan Buchman
fd4db8dfdc Merge pull request #1676 from tendermint/xla/collapse-peerconfig
Collapse PeerConfig into P2PConfig
2018-06-04 18:50:41 -07:00
Alexander Simmerl
1318bd18cd Merge pull request #1680 from Slamper/develop
Return 404 for unknown RPC endpoints
2018-06-05 02:14:16 +02:00
Alexander Simmerl
ea896865a7 Collapse PeerConfig into P2PConfig
As both configs are concerned with the p2p packaage and PeerConfig is
only used inside of the package there is no good reason to keep the
couple of fields separate, therefore it is collapsed into the more
general P2PConifg. This is a stepping stone towards a setup where the
components inside of p2p do not have any knowledge about the config.

follow-up to #1325
2018-06-05 02:07:56 +02:00
Ethan Buchman
aeb91dfc22 dev version bump 2018-06-04 15:57:57 -07:00
Ethan Buchman
5727916c5b Merge pull request #1681 from tendermint/release/v0.19.8
Release/v0.19.8
2018-06-04 15:48:22 -07:00
Ethan Buchman
876c8f14e7 changelog and version 2018-06-04 14:16:58 -07:00
Hendrik Hofstadt
67416feb3a return 404 for unknown RPC endpoints 2018-06-04 22:14:20 +02:00
Zach Ramsay
8706ae765c docs: a link to quick install script 2018-06-04 10:42:28 -04:00
Zach Ramsay
954a8941ff scripts: quickest/easiest fresh install 2018-06-04 10:42:28 -04:00
Anton Kaliaev
1f22f34edf flush wal group on stop
Refs #1659
Refs https://github.com/tendermint/tmlibs/pull/217
2018-06-04 16:47:44 +04:00
Anton Kaliaev
0562009275 bring back assert 2018-06-04 16:33:57 +04:00
idoor88
fedd07c522 removed assertion to avoid confusion (#1626) 2018-06-04 14:30:46 +04:00
Anton Kaliaev
3fa734ef5a recheck only if there are txs left in the mempool (#1645) 2018-06-04 14:28:47 +04:00
Ethan Buchman
cd6bfdc42f Merge pull request #1673 from tendermint/bucky/mempool
fix possible mempool deadlock
2018-06-03 16:14:58 -04:00
Ethan Buchman
98b0c51b5f fix possible mempool deadlock 2018-06-03 16:11:52 -04:00
Ethan Buchman
c777be256a changelog, version 2018-06-03 16:11:21 -04:00
Ethan Buchman
d66f8bf829 Merge branch 'master' into develop 2018-06-03 16:10:04 -04:00
Alexander Simmerl
bf370d36c2 Extract priv_validator into first class package
This is a maintenance change to move the private validator package out
of the types and to a top-level location. There is no good reason to
keep it under the types and it will more clearly coommunicate where
additions related to the privval belong. It leaves the interface and the
mock in types for now as it would introduce circular dependency between
privval and types, this should be resolved eventually.

* mv priv_validator to privval pkg
* use consistent `privval` as import

Follow-up to #1255
2018-06-03 13:51:58 +02:00
Ethan Buchman
1c643701f5 Merge pull request #1662 from Liamsi/develop
WIP: simplify & update documentation, fix typo
2018-06-02 18:39:36 -04:00
Alexander Simmerl
0b0290bdb2 Merge pull request #1675 from tendermint/xla/disable-slate-ci
Disable slate step in CI workflow
2018-06-02 15:56:43 +02:00
Alexander Simmerl
a4779fdf51 Disable slate step in CI workflow
It's currently breaking for unknown reasons, until fixed we going to
disable it, to not block on it for unrelated PRs.
2018-06-02 15:49:25 +02:00
Liamsi
7030d5c2a7 remove notes column
according to: https://github.com/tendermint/go-crypto/pull/110#issuecomment-394048086
2018-06-02 13:04:40 +01:00
Ethan Buchman
f34d1009c4 Merge pull request #1671 from tendermint/1518-xla/remove-auth_enc-option
Remove auth_enc config option
2018-06-01 21:07:14 -04:00
Alexander Simmerl
0e3dc32b3d Merge pull request #1672 from tendermint/xla/store-ci-test-logs
Store CI test logs
2018-06-02 02:44:01 +02:00
Alexander Simmerl
d292fa4541 Store CI test logs
For post-mortem introspection it is helpful to have the full logs of
test runs available for download.
2018-06-02 02:33:31 +02:00
Alexander Simmerl
3255c076e5 Remove auth_enc config option
As we didn't hear any voices requesting this feature, we removed the
option to disable it and always have peer connection auth encrypted.

closes #1518
follow-up #1325
2018-06-01 21:07:20 +02:00
Liamsi
978277a4c1 make slightly more readable 2018-05-31 20:40:01 +01:00
Liamsi
58eb76f34d simplify & update documentation, fiy typo 2018-05-31 20:13:41 +01:00
Ethan Buchman
a017f2fdd4 Merge pull request #1654 from tendermint/release/v0.19.7
Release/v0.19.7
2018-05-31 09:15:13 -04:00
Ethan Buchman
aaaa5f23e2 changelog and version 2018-05-30 23:36:36 -04:00
Ethan Buchman
178e357d7f Merge pull request #1618 from tendermint/1494-production-notes
[docs] notes about running a production system
2018-05-30 23:23:51 -04:00
Ethan Buchman
683b527534 Merge pull request #1636 from tendermint/bucky/docs
gut docs/app-arch
2018-05-30 23:17:26 -04:00
Ethan Buchman
d584e03427 fix link and typo 2018-05-30 23:23:39 -04:00
Ethan Buchman
d454b1b25f SkipDuplicate -> AllowDuplicate; fix p2p test on mac 2018-05-30 21:44:39 -04:00
Ethan Buchman
432f21452d Merge branch 'master' into develop 2018-05-30 21:43:31 -04:00
Anton Kaliaev
f0ce8b3883 note about state syncing 2018-05-30 16:55:39 +04:00
Anton Kaliaev
3da5198631 fixes after @zramsay's review 2018-05-30 16:51:20 +04:00
Anton Kaliaev
252a0a392b move reactor descriptions to relevant specs 2018-05-30 16:51:19 +04:00
Anton Kaliaev
f7106bfb39 more config variables
Refs #1494
2018-05-30 16:51:19 +04:00
Anton Kaliaev
2a517ac98c hardware specs and configuration params
Refs #1494
2018-05-30 16:51:19 +04:00
Anton Kaliaev
b542dce2e1 [docs] signal handling
Refs #1494
2018-05-30 16:51:19 +04:00
Anton Kaliaev
82ded582f2 [docs] debugging/monitoring sections, restart handling
Refs #1494
2018-05-30 16:51:19 +04:00
Anton Kaliaev
e0d4fe2dba document DOS exposure and mitigation
Refs #1494
2018-05-30 16:51:19 +04:00
Anton Kaliaev
83c6f2864d document the consensus WAL
Refs #1494
2018-05-30 16:51:19 +04:00
Anton Kaliaev
33ec8cb609 document logging
Refs #1494
2018-05-30 16:51:19 +04:00
Ethan Buchman
43a652bcbf Merge pull request #1647 from tendermint/1643-events-query-pubsub
[docs] indexing transactions and subscribing to events
2018-05-30 08:16:08 -04:00
Ethan Buchman
094a40084d Merge pull request #1646 from tendermint/xla/duplicate-ip-check-config
Introduce option to skip duplicate ip check
2018-05-30 08:12:46 -04:00
Anton Kaliaev
eec9f142b5 [docs] indexing transactions and subscribing to events
Refs #1643
2018-05-30 13:10:04 +04:00
Alexander Simmerl
5796e879b9 Introduce option to skip duplicate ip check
In some scenarios like tests we want to disable the guard which prevents
peers connecting from the same ip.

Fixes #1632
Closes #1634
2018-05-30 10:40:22 +02:00
Ethan Buchman
846ca5ce56 Merge pull request #1641 from tendermint/release/v0.19.6
Release/v0.19.6
2018-05-29 13:14:44 -04:00
Jae Kwon
fd6021876b Potential fix for blockchain pool halting issue 2018-05-29 12:32:22 -04:00
Ethan Buchman
2763c8539c changelog and version 2018-05-29 12:31:01 -04:00
Ethan Buchman
1c0bfe1158 Merge pull request #1633 from tendermint/jae/blockchain_pool
Potential fix for blockchain pool halting issue
2018-05-29 10:27:53 -04:00
Ethan Buchman
1e87ef7f75 circle: add GOCACHE=off and -v to tests 2018-05-29 09:28:29 -04:00
Ethan Buchman
c8be091d4a gut docs/app-arch 2018-05-28 16:58:38 -04:00
Zach
ec34c8f9d2 docs: update ABCI output (#1635) 2018-05-28 22:06:02 +04:00
Anton Kaliaev
6004587347 expect all tags to be strings (#1498)
* expect all tags to be strings

Refs #1369

* port changes from https://github.com/tendermint/tmlibs/pull/204

Refs #1369
2018-05-28 14:37:11 +04:00
Jae Kwon
f55725ebfa Potential fix for blockchain pool halting issue 2018-05-26 22:08:42 -07:00
Zach
7f20eb5f8e generate RPC docs using Slate (#1612)
* generate RPC docs using Slate (#691)

* update changelog

* skip if branch not develop

* slate: only build if rpc/core has changes

* fetch develop to compare against

* slate: build on master only

* [rpc/core] use original repo, not fork in README
2018-05-25 15:59:24 +04:00
Anton Kaliaev
eeabb4c06b Merge pull request #1607 from tendermint/1600-wal-bug
[wal] small fixes in SearchEndHeight & replay logic
2018-05-25 15:41:57 +04:00
Anton Kaliaev
4da81aa0b7 commented out TestPEXReactorRunning 2018-05-25 15:11:32 +04:00
Anton Kaliaev
67068a34f2 log requesting addresses 2018-05-25 15:11:32 +04:00
Anton Kaliaev
2a0e9f93ce provide arg to error
BEFORE:

```
E[05-24|11:55:37.229] Dialing failed                               pex=0 addr=022ec801d79025caab3afbbf816d92ff8450d040@127.0.0.2:6593 err="Connect to self: <nil>" attempts=0
```

AFTER:

```
E[05-24|11:55:37.229] Dialing failed                               pex=0 addr=022ec801d79025caab3afbbf816d92ff8450d040@127.0.0.2:6593 err="Connect to self: 022ec801d79025caab3afbbf816d92ff8450d040@127.0.0.2:6593" attempts=0
```
2018-05-25 15:11:32 +04:00
Anton Kaliaev
708f35e5c1 do not look for height in older files if we've seen height - 1
Refs #1600
2018-05-25 15:11:15 +04:00
Anton Kaliaev
f3f5c7f472 we must only return io.EOF to progress to the next file in auto.Group
since we never write msg partially, if we've encountered io.EOF in the
middle of the msg, we must abort
2018-05-25 15:10:51 +04:00
Anton Kaliaev
68f6226bea data is corrupted, but this requires manual intervention
i.e., can't be skipped

and we should only return DataCorruptionError if we can skip a msg safely
2018-05-25 15:10:51 +04:00
Anton Kaliaev
118b86b1ef fix nil panic error
msg is nil and if we continue executing, we'll get nil exception at
`msg.Msg.(....)`
2018-05-25 15:10:51 +04:00
Anton Kaliaev
b9afcbe3a2 fix typo 2018-05-25 15:10:51 +04:00
Anton Kaliaev
a885af0826 Merge pull request #1574 from tendermint/847-separate-internal-pubsub
[pubsub] Prioritise internal subscribers (e.g. reactor) over external (e.g. RPC)
2018-05-24 21:09:56 +04:00
Ethan Buchman
3a947b0117 Merge pull request #1619 from tendermint/zach/cleaner-repo
clean up links & spec docs
2018-05-23 21:09:15 -04:00
Ethan Buchman
caf5afc084 Merge pull request #1520 from tendermint/bucky/p2p-same-ip
p2p: prevent connections from same ip
2018-05-23 20:57:17 -04:00
Zach Ramsay
2aa5285c66 fix from self-review 2018-05-23 10:08:57 -04:00
Zach Ramsay
b166831fb5 link to both consensus specs 2018-05-23 10:05:03 -04:00
Zach Ramsay
423fef1416 docs: use absolute links (#1617) 2018-05-23 10:01:32 -04:00
Zach Ramsay
b4d10b5b91 consensus: link to spec from readme (#1609) 2018-05-23 09:41:54 -04:00
Ethan Buchman
6f1bfb6280 Merge pull request #1616 from tendermint/zach/no-debora
remove debora scripts
2018-05-23 08:43:22 -04:00
Ethan Buchman
5e7177053c Merge pull request #1611 from tendermint/zach/dead-links
fix dead links & other doc updates
2018-05-23 08:42:25 -04:00
Zach Ramsay
a0201e7862 docker readme: update 2018-05-23 08:28:55 -04:00
Zach Ramsay
126ddca1a6 remove debora scripts (#1610) 2018-05-23 08:01:07 -04:00
Alexander Simmerl
186d38dd8a Use different loopback addresses for test switch 2018-05-23 02:36:48 +02:00
Alexander Simmerl
01fd102dba Incoporate review feedback 2018-05-23 01:56:03 +02:00
Alexander Simmerl
e11f3167ff Fix pex reactor test 2018-05-23 01:35:03 +02:00
Alexander Simmerl
7d98cfd3d6 Test duplicate IP guard in peer set 2018-05-23 01:24:27 +02:00
Alexander Simmerl
4848e88737 Fix persistent peer switch test 2018-05-23 00:24:40 +02:00
Zach Ramsay
60d7486de2 docs: fix dead links, closes #1608 2018-05-22 14:46:56 -04:00
Ethan Buchman
229c18f1bd Merge branch 'master' into develop 2018-05-21 16:13:11 -04:00
Alexander Simmerl
91b6d3f18c Do not set address for self error 2018-05-21 18:47:14 +02:00
Alexander Simmerl
20e9dd0737 Return fake IP even when there is no conn 2018-05-21 17:55:40 +02:00
Alexander Simmerl
7b02b5b66b Add RemoteIP to test implementation 2018-05-21 17:41:34 +02:00
Alexander Simmerl
0cd92a4948 Fix race in test suffix 2018-05-21 17:35:49 +02:00
Ethan Buchman
747f28f85f Merge pull request #1602 from tendermint/bucky/readme
update readme
2018-05-21 09:27:15 -04:00
Anton Kaliaev
a9d0adbdef update changelog 2018-05-21 10:56:33 +04:00
Anton Kaliaev
3485edf4f5 update test docker image Go version to 1.10 2018-05-21 10:51:47 +04:00
Anton Kaliaev
c6f612bfc3 subscribe before state emits NewRoundStep
I had to alter events package for that. Hope that's fine.
Refs #847
2018-05-21 10:51:47 +04:00
Anton Kaliaev
bb9aa85d22 copy events and pubsub packages from tmlibs
Refs #847
2018-05-21 10:51:47 +04:00
Anton Kaliaev
c4fef499b6 switch to events package 2018-05-21 10:50:55 +04:00
Anton Kaliaev
b77d5344fc rename methods for clarity 2018-05-21 10:50:55 +04:00
Anton Kaliaev
21f5f3faa7 use channels to send votes, ... from consensus state to reactor
Refs #847
2018-05-21 10:50:55 +04:00
Ethan Buchman
bf6527fc59 Merge pull request #1382 from EugeneChung/develop
remove Heap.Update() call when setting Proposer field
2018-05-20 19:32:13 -04:00
Ethan Buchman
ed8d9951c0 point to terraform-ansible docs 2018-05-20 17:05:57 -04:00
Ethan Buchman
97b39f340e update readme 2018-05-20 17:01:15 -04:00
Ethan Buchman
383c255f35 dev version bump 2018-05-20 16:54:21 -04:00
Ethan Buchman
931fb385d7 Merge pull request #1599 from tendermint/release/v0.19.5
Release/v0.19.5
2018-05-20 16:45:00 -04:00
Ethan Buchman
018e096748 Merge pull request #1601 from tendermint/bucky/wal-sync
consensus: only fsync wal after internal msgs
2018-05-20 16:36:33 -04:00
Ethan Buchman
ee4eb59355 update comments 2018-05-20 16:44:08 -04:00
Ethan Buchman
082a02e6d1 consensus: only fsync wal after internal msgs 2018-05-20 14:40:47 -04:00
Ethan Buchman
2c40966e46 fix changelog 2018-05-20 14:08:35 -04:00
Ethan Buchman
0a9dc9f875 changelog 2018-05-20 10:25:21 -04:00
Ethan Buchman
87cefb724d version 2018-05-20 10:22:42 -04:00
Ethan Buchman
6701dba876 changelog 2018-05-20 10:22:22 -04:00
Ethan Buchman
442bbe592f Merge pull request #1598 from tendermint/bucky/docs-clean
Bucky/docs clean
2018-05-20 09:46:09 -04:00
Ethan Buchman
301aa92f9c phony 2018-05-20 09:53:38 -04:00
Ethan Buchman
52f27686ef Merge pull request #1567 from tendermint/909-limit-tx-search-output
limit /tx_search output
2018-05-20 09:44:41 -04:00
Ethan Buchman
6f9867cba6 fix validate pagination params 2018-05-20 01:47:15 -04:00
Ethan Buchman
02615c8695 update readme 2018-05-20 00:41:54 -04:00
Ethan Buchman
2df137193c security.md 2018-05-20 00:33:37 -04:00
Ethan Buchman
1ef415728d docs/spec: blockchain and consensus dirs 2018-05-20 00:28:47 -04:00
Ethan Buchman
773e3917ec networks: update readmes 2018-05-19 23:35:45 -04:00
Ethan Buchman
26fdfe10fd update readme 2018-05-19 23:28:27 -04:00
Ethan Buchman
d76e2dc3ff readme.rst -> readme.md 2018-05-19 23:26:02 -04:00
Ethan Buchman
420f925a4d link bug bounty in readme 2018-05-19 23:21:42 -04:00
Ethan Buchman
d7d12c8030 update networks/local readme 2018-05-19 23:21:35 -04:00
Ethan Buchman
6c4a26f248 update readme 2018-05-19 22:44:29 -04:00
Ethan Buchman
2a26c47da5 Merge pull request #1590 from tendermint/1227-msg-bytes
nice output for msgBytes
2018-05-18 19:17:22 -04:00
Ethan Buchman
aabe96f1af Merge pull request #1594 from tendermint/zach/tests-less-bash
test cleanup
2018-05-18 19:00:44 -04:00
Zach Ramsay
0e1f730fbb rm unused file, fix docker-compose.yml 2018-05-18 14:12:01 -04:00
Zach Ramsay
0b68ec4b8e move a file to remove a directory 2018-05-18 13:37:58 -04:00
Zach Ramsay
ca120798e4 s/dummy/kvstore/g for compatibility (#1532) 2018-05-18 13:26:26 -04:00
Zach Ramsay
595fc24c56 remove very old bash file 2018-05-18 13:22:04 -04:00
Anton Kaliaev
4611cf44f0 Merge pull request #1591 from tendermint/zach/dawks
docs improvements
2018-05-18 18:32:43 +04:00
Alexander Simmerl
d596ed1bc2 Let peerConn handle IPs in for tests 2018-05-18 16:27:57 +02:00
Zach Ramsay
0fb33ca91d docs: update install instructions, closes #1580 2018-05-18 10:12:52 -04:00
Zach Ramsay
35428ceb53 docs: lil fixes 2018-05-18 10:01:56 -04:00
Ethan Buchman
de8d4325de Merge pull request #1585 from tendermint/345-mempool-cache
Mempool cache
2018-05-18 08:54:47 -04:00
Anton Kaliaev
5a041baa36 nice output for msgBytes
Closes #1227
2018-05-18 12:45:09 +04:00
Anton Kaliaev
202a43a5af remove TODO
no longer relevant, I guess. since ABCI only defines 0 (success) code.
2018-05-18 10:48:13 +04:00
Anton Kaliaev
2987158a65 [docs] add a note about replay protection
Refs #345, https://github.com/tendermint/tendermint/issues/458#issuecomment-297077148
2018-05-18 10:45:51 +04:00
Anton Kaliaev
c9001d5a11 bound the mempool
Refs #345
2018-05-18 10:45:51 +04:00
Anton Kaliaev
90446261f3 [docs] document transactional semantics
Refs #1494, #345
2018-05-18 10:45:51 +04:00
Anton Kaliaev
ae572b9038 remove extra call to Exists
Refs #345

https://github.com/tendermint/tendermint/issues/1539#issuecomment-387240606
2018-05-18 10:17:09 +04:00
Zach
0908e668bd document testnet command, closes #1535 (#1588) 2018-05-18 09:52:31 +04:00
Ethan Buchman
e0dbc3673c version bump 2018-05-17 22:28:53 -04:00
Ethan Buchman
545990f845 Merge pull request #1587 from tendermint/release/v0.19.4
Release/v0.19.4
2018-05-17 22:20:17 -04:00
Ethan Buchman
19ccd1842f version and changelog 2018-05-17 15:47:07 -04:00
Ethan Buchman
b4d6bf7697 add back new-spec/README to tell people it moved 2018-05-17 15:39:49 -04:00
Ethan Buchman
1854ce41fc Merge pull request #1586 from tendermint/bucky/add-part-fix
Bucky/add part fix
2018-05-17 15:21:29 -04:00
Ethan Buchman
547e8223b9 fix 2018-05-17 15:24:37 -04:00
Ethan Buchman
8e46df14e7 improve consensus logger 2018-05-17 13:59:41 -04:00
Anton Kaliaev
8d60a5a7bd update changelog 2018-05-17 21:25:45 +04:00
Anton Kaliaev
5115618550 add limit param to /unconfirmed_txs 2018-05-17 21:25:04 +04:00
Anton Kaliaev
a6b74b82d1 limit /tx_search output
Refs #909
2018-05-17 21:25:03 +04:00
Ethan Buchman
e5220360c5 AddPart always verifies 2018-05-17 13:17:50 -04:00
Zach
b5c4098c53 update docs/examples & terraform/ansible (#1534)
* update docs/examples

* ansible: add node IDs from docs/examples

* better monikers

* ansible: clearer paths

* upgrade version

* examples: updates

* docs: consolidate terraform & ansible

* remove deprecated info, small reorgs

* docs build fix

* docs: t&a critical commit

* s/dummy/kvstore/g

* terraform/DO region unavailable, persistent error can't be bothered to debug rn

* terraform: need vars

* networks: t&a standalone integration script for DO

* t&a more updates

* examples: add script that shows what the testnet command does

* use AMS3, since AMS2 is not available
2018-05-17 18:05:59 +04:00
Anton Kaliaev
bc8768cfea Merge pull request #1550 from tendermint/perf-improvements
Performance improvements
2018-05-17 10:50:28 +04:00
Anton Kaliaev
d832bde280 update Vagrantfile 2018-05-17 10:43:38 +04:00
Anton Kaliaev
5e3a23df6d simplify indexer service main loop 2018-05-17 10:00:59 +04:00
Anton Kaliaev
6f7333fd5f fix tests 2018-05-17 10:00:59 +04:00
Anton Kaliaev
58e3246ffc batch index txs 2018-05-17 10:00:59 +04:00
Anton Kaliaev
bbe1355957 log only hash, not tx itself 2018-05-17 10:00:59 +04:00
Anton Kaliaev
7c14fa820d do not log txs at info level
BEFORE:

```
./tm-bench -c 5 -r 1000 127.0.0.1:46657
Stats          Avg       StdDev     Max
Txs/sec        1826      843        2744
Blocks/sec     1.100     0.300      2
```

AFTER:

```
./tm-bench -T 30 -c 5 -r 1000 127.0.0.1:46657
Stats          Avg       StdDev     Max
Txs/sec        6120      1970       9776
Blocks/sec     1.000     0.000      1
```
2018-05-17 10:00:59 +04:00
Anton Kaliaev
0d93424c6a disable indexer by default 2018-05-17 10:00:59 +04:00
Anton Kaliaev
efc01cf582 stop localnet before starting
in order to avoid having to stop it manually
2018-05-17 10:00:58 +04:00
Zach
754be1887c spec: move to final location (#1576) 2018-05-17 09:58:15 +04:00
Zach
775b015173 docs: add diagram, closes #1565 (#1577) 2018-05-17 09:57:28 +04:00
Alexander Simmerl
b698a9febc Remove double locking in HasIP 2018-05-16 19:21:12 +02:00
Alexander Simmerl
c5f45275ec Use remotePeer for test switch 2018-05-16 19:21:12 +02:00
Alexander Simmerl
77f09f5b5e Move to ne.IP 2018-05-16 19:21:12 +02:00
Ethan Buchman
1fe41be929 p2p: prevent connections from same ip 2018-05-16 19:21:12 +02:00
Ethan Buchman
68a0b3f95b version bump. add roadmap back. minor fixes 2018-05-15 22:42:29 -04:00
Ethan Buchman
b1f3c11948 Merge branch 'master' into develop 2018-05-15 22:41:03 -04:00
Jae Kwon
e1a3f16fa4 Comment tweaks 2018-05-15 08:48:59 -07:00
Ethan Buchman
aab98828fe Merge pull request #1570 from tendermint/release/v0.19.3
Release/v0.19.3
2018-05-15 08:44:16 -04:00
Ethan Buchman
03f6a29a64 changelog and version 2018-05-14 17:00:57 -04:00
Ethan Buchman
4851653d8e Merge pull request #1569 from tendermint/bucky/update-valid-block-rule
Fix validBlock rule
2018-05-14 16:48:20 -04:00
Ethan Buchman
162811476a update some comments 2018-05-14 16:32:19 -04:00
Zarko Milosevic
b5ac9ede8a Add rules in gossipVotesForHeight to clarify priorities on messages to send 2018-05-14 16:18:50 -04:00
Jae Kwon
ff5dfc0c15 Add more comments for Valid* 2018-05-14 16:18:50 -04:00
Jae Kwon
d3a98675aa Refactor addVote() to be clearer 2018-05-14 16:17:21 -04:00
Jae Kwon
e3c4625e63 Suggested changes to consensus/reactor.go 2018-05-14 16:17:21 -04:00
Zarko Milosevic
01ac378c96 Update condition based on Jae input 2018-05-14 16:17:21 -04:00
Zarko Milosevic
83ca46396d Update gossipVotes routine to align with validBlock mechanism 2018-05-14 16:17:21 -04:00
Zarko Milosevic
2c125b6c78 Fix validValue rule 2018-05-14 16:17:21 -04:00
Ethan Buchman
3dde0584ed Merge pull request #1529 from tendermint/greg/persistent-script-fix
Persistence test bash fix for relative folder path
2018-05-14 15:44:27 -04:00
Greg Szabo
4bca7c1009 Added tendermint/testing docker image description 2018-05-14 12:24:54 -04:00
Greg Szabo
4be3ffbe9b Persistence test bash fix for relative folder path 2018-05-14 12:24:54 -04:00
Ethan Buchman
5b9a1423ae Merge pull request #1564 from tendermint/bucky/dump-consensus
Improve consensus state RPC
2018-05-14 12:21:54 -04:00
Ethan Buchman
16932f889f changelog 2018-05-14 10:45:18 -04:00
Ethan Buchman
e9804d76cf fixes from review 2018-05-14 10:33:31 -04:00
Ethan Buchman
a41f0d3891 rpc: /consensus_state for simplified output 2018-05-13 19:53:54 -04:00
Ethan Buchman
658060150c rpc: add voting power totals to vote bitarrays 2018-05-13 19:22:23 -04:00
Ethan Buchman
d0229e8b1e Merge pull request #1554 from tendermint/jae/expose_peer_stats
Expose peer stats for dump_consensus_state
2018-05-13 16:16:35 -04:00
Jae Kwon
56c9e0da7e Add back sample output in rpc/core/consensus.go; Tweak DumpConsensusState output for peers 2018-05-12 15:39:30 -07:00
Ethan Buchman
fbe253767e Merge pull request #1540 from tendermint/set-genesis-time-on-init
set GenesisTime to now during `tendermint init`
2018-05-12 10:10:06 -04:00
Jae Kwon
edbec10f9e Expose peer stats for dump_consensus_state 2018-05-10 22:43:21 -07:00
Allen
c0a1a8d3c0 add link to github (#1542) 2018-05-09 12:13:07 +04:00
Anton Kaliaev
ac2d3a917e set GenesisTime to now during tendermint init 2018-05-08 12:04:20 +04:00
Ethan Buchman
64408a4041 Merge pull request #1528 from tendermint/release/v0.19.2
Release/v0.19.2
2018-04-30 18:28:38 -04:00
Ethan Buchman
cae31157b1 fix lint 2018-04-30 18:23:02 -04:00
Ethan Buchman
66c2b60324 version and changelog 2018-04-30 16:06:45 -04:00
Ethan Buchman
e2e2127365 Merge pull request #1519 from tendermint/bucky/p2p-cleanup
Cleanup P2P
2018-04-30 15:54:04 -04:00
Ethan Buchman
f395b82f73 node: remove commented out trustMetric 2018-04-30 15:59:05 -04:00
Ethan Buchman
47557f868a create addrbook even if pex=false. fixes #1525 2018-04-30 08:31:03 -04:00
Ethan Buchman
b6c062c451 fixes from review 2018-04-30 08:19:19 -04:00
Max Levy
12fc396101 Split CMD's param on space (#1523)
This is to avoid "ERROR: unknown flag: --proxy_app dummy" message when running "docker-compose up"
2018-04-29 17:35:10 +03:00
Ethan Buchman
c195772de1 p2p: small lint 2018-04-28 21:17:28 -04:00
Ethan Buchman
d3c4f746a7 spec: abci notes. closes #1257 2018-04-28 21:12:25 -04:00
Ethan Buchman
fae94a44a2 p2p/pex: some addrbook fixes
* fix before/after in isBad()
* allow multiple IPs per ID even if ID isOld
2018-04-28 20:09:02 -04:00
Ethan Buchman
3a30ee75b9 minor fixes 2018-04-28 17:27:51 -04:00
Ethan Buchman
3498b676a6 update spec and addrbook.go 2018-04-28 17:14:58 -04:00
Ethan Buchman
6157c700dd forgot errors file 2018-04-28 16:15:30 -04:00
Ethan Buchman
c90bf77566 rpc: add n_peers to /net_info 2018-04-28 16:09:18 -04:00
Ethan Buchman
6805ddf1b8 p2p: change some logs from Error to Debug. #1476 2018-04-28 16:00:45 -04:00
Ethan Buchman
2761861b6b p2p: MinNumOutboundPeers. Closes #1501 2018-04-28 15:52:05 -04:00
Ethan Buchman
64569b15e5 fix build and test 2018-04-28 15:39:09 -04:00
Ethan Buchman
0450e35d67 some comments 2018-04-28 15:19:33 -04:00
Ethan Buchman
268055e549 node: remove dup code from rebase 2018-04-28 15:04:37 -04:00
Ethan Buchman
aaa81092e7 p2p: some comments and a log line 2018-04-28 15:01:33 -04:00
Ethan Buchman
3ee1d7909e p2p: explicit netaddress errors 2018-04-28 14:48:51 -04:00
Ethan Buchman
32268a8135 limit maxPexMessageSize based on maxAddressSize 2018-04-28 14:41:36 -04:00
Ethan Buchman
f645187122 spec: pex update 2018-04-28 13:11:32 -04:00
Ethan Buchman
40c79235c0 p2p: dont require minor versions to match in handshake 2018-04-28 13:09:17 -04:00
Ethan Buchman
c23909eecf p2p/pex: minor cleanup and comments 2018-04-28 13:08:44 -04:00
Ethan Buchman
936d1a0e68 some notes about the p2p layer 2018-04-28 11:35:09 -04:00
Ethan Buchman
0cbbb61962 minor cleanup 2018-04-28 01:02:39 -04:00
Ethan Buchman
fa66694f2e Merge branch 'develop' into fix-persistent-first 2018-04-28 00:34:03 -04:00
Ethan Buchman
d92def4b60 version bump 2018-04-28 00:06:05 -04:00
Ethan Buchman
26f633ed48 Merge pull request #1514 from tendermint/release/v0.19.1
Release/v0.19.1
2018-04-27 23:36:15 -04:00
Ethan Buchman
79bfbebfff rpc: docs/comments 2018-04-27 23:19:40 -04:00
Ethan Buchman
f33da8817a rpc: lower_case peer_round_states, use a list, add the node_address 2018-04-27 23:00:09 -04:00
Ethan Buchman
ffe81a0206 changelog and version 2018-04-27 12:35:21 -04:00
Ethan Buchman
0e00154fcc Merge branch 'master' into develop 2018-04-27 12:23:12 -04:00
Ethan Buchman
1ab89e6cbf update changelog 2018-04-27 12:23:00 -04:00
Ethan Buchman
14cff484f1 Merge pull request #1440 from tendermint/1428-remove-wal-light
[config] remove wal_light setting
2018-04-27 12:06:51 -04:00
Ethan Buchman
25cee8827a Merge branch 'develop' into 1428-remove-wal-light 2018-04-27 12:06:08 -04:00
Jae Kwon
65ebbccb74 Add GoAmino DeepCopy() benchmark for RoundState 2018-04-27 11:55:45 -04:00
Ethan Buchman
1188dfe7ee Merge pull request #1511 from tendermint/bucky/rpc-fixes
Various RPC fixes
2018-04-27 11:45:46 -04:00
Ethan Buchman
c45ba2967a fixes from review 2018-04-27 10:29:05 -04:00
Ethan Buchman
f67c5a9e7b forgot wire.go file 2018-04-27 10:00:34 -04:00
Ethan Buchman
593a785ae2 set NodeInfo on switch before starting RPC server
should fix #1199
2018-04-26 23:49:48 -04:00
Ethan Buchman
94e823cc91 p2p: NodeInfo.Channels is HexBytes 2018-04-26 23:43:51 -04:00
Ethan Buchman
47e4d64973 add validator address to /status 2018-04-26 23:43:51 -04:00
Ethan Buchman
a2d77cbe4e add MarshalJSON methods to fix dump_consensus_state 2018-04-26 23:43:48 -04:00
Ethan Buchman
390b592dec Merge pull request #1510 from tendermint/bucky/docs-and-fixes
JSON Indent and some docs
2018-04-26 23:03:47 -04:00
Ethan Buchman
9ab1fafdf1 some amino json for #1504 2018-04-26 22:06:15 -04:00
Ethan Buchman
94c016a04e use MarshalJSONIndent for init files. closes #1506 2018-04-26 21:32:18 -04:00
Ethan Buchman
97f3ada9c2 update godep 2018-04-26 21:31:48 -04:00
Ethan Buchman
d7d4471072 Merge pull request #1507 from tendermint/bucky/docs-pre-amino
document pre-amino pubkeys/addresses
2018-04-26 20:40:53 -04:00
Ethan Buchman
d48a6f930d document pre-amino pubkeys/addresses 2018-04-26 20:46:08 -04:00
Ethan Buchman
389a6ffa16 Merge pull request #1500 from tendermint/bucky/spec-updates
Bucky/spec updates
2018-04-26 11:44:27 -04:00
Ethan Buchman
f1ead2df70 typo 2018-04-26 11:50:45 -04:00
Ethan Buchman
e5951acfb4 SHA256 -> RIPEMD160 2018-04-26 11:47:13 -04:00
Ethan Buchman
0e1414ef9d spec: add Address spec. notes about Query 2018-04-26 11:46:20 -04:00
Ethan Buchman
97be1eef87 add abci notes 2018-04-26 11:08:34 -04:00
Anton Kaliaev
0d9004a854 [cmd] Turn off strict routability when using testnet cmd (#1493)
* [cmd] Turn off strict routability when using testnet cmd

Refs https://github.com/tendermint/tendermint/pull/1454

* use "testnet" instead of "it"
2018-04-26 16:52:11 +02:00
Ethan Buchman
91c81ef9a1 spec: note on byte arrays, clean up bitarrays and more, add merkle proof, add crypto.go script 2018-04-26 10:42:58 -04:00
Ethan Buchman
e2f0778c14 spec: update encoding.md 2018-04-26 09:36:41 -04:00
Anton Kaliaev
63f8c58009 Merge pull request #1471 from tendermint/greg/devopstools
Greg/devopstools
2018-04-25 10:37:28 +02:00
Greg Szabo
9ba208c1f5 wrapper.sh logfile check fix 2018-04-24 16:40:51 -04:00
Greg Szabo
6ce6b20993 Renamed remotenet to sentrynet to match the purpose better. 2018-04-24 14:22:19 -04:00
Anton Kaliaev
5361073439 Merge pull request #1483 from tendermint/jae/lower_case_round_state
Jae/lower case round state
2018-04-24 09:57:42 +02:00
suyuhuang
6c04465d3d Fix Prove int abci.ABCIQuery (#1485)
* fix Prove in abci query

* fix Prove in abci query

* fix doc

* fix doc
2018-04-24 09:56:25 +02:00
Greg Szabo
089ce6744c Added ansible playbook to remote networks to ship logs to logz.io 2018-04-23 22:38:49 -04:00
Max Levy
17a5c6fa1a typo fix 2018-04-23 21:03:34 +02:00
Rigel
18c3f8f3f1 writeDefaultCondigFile -> writeDefaultConfigFile (#1490) 2018-04-23 21:01:40 +02:00
Jae Kwon
b42d5a2211 blockID -> block_id for JSON 2018-04-21 20:24:50 -07:00
Jae Kwon
b20e777f53 lower_case json field names 2018-04-20 23:20:44 -07:00
Greg Szabo
659762736c Makefile targets for remotenet fixed 2018-04-18 05:56:13 -04:00
Anton Kaliaev
ece3f678da [docs/spec] update msg type and Tendermint behavior (#1468)
Refs #1422
2018-04-17 19:38:10 +02:00
Greg Szabo
5b5acbb343 Ansible README update and small fixes 2018-04-17 12:28:05 -04:00
Ethan Buchman
a2930cd723 Merge pull request #1474 from tendermint/release/v0.19.0
Release/v0.19.0
2018-04-17 10:59:36 +02:00
Ethan Buchman
45a05b4726 Merge pull request #1461 from tendermint/update-changelog
update changelog
2018-04-17 09:56:53 +02:00
Greg Szabo
8bdfe15de9 Dockerfile, localnode, sentry node scripts changes
- Updated Dockerfile and created build-docker target
- Changed localnode docker image to set permissions to more permissive (docker has different user than host system)
- Added sentry node terraform and ansible script
2018-04-16 11:34:01 -04:00
Greg Szabo
b3904b8da8 ShellChecked wrapper.sh 2018-04-13 21:34:05 -04:00
Greg Szabo
f2dae2a2d8 Moved to networks folder, introduced cloud server scripts using terraform and ansible (sentry nodes) 2018-04-13 21:03:25 -04:00
Anton Kaliaev
1706ce6f7f update changelog for 0.19.0 release 2018-04-13 10:50:34 +02:00
Jae Kwon
d0beaba7e8 Bump version to 0.19.0 2018-04-13 01:32:47 -07:00
Anton Kaliaev
c28784de5e Merge pull request #1453 from tendermint/fix-localnet
Fix permissions and folder structure for localnet
2018-04-12 17:50:08 +02:00
Anton Kaliaev
d06390638d [localnet] use routable IPs 2018-04-12 16:02:31 +02:00
Anton Kaliaev
3a0edc561d log error from AddrBook#AddAddress in DialPeersAsync
Refs #1434
2018-04-12 15:51:17 +02:00
Anton Kaliaev
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
Anton Kaliaev
5babaf9a88 [localnet] fix folder permissions errors 2018-04-12 15:51:17 +02:00
Greg Szabo
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
Anton Kaliaev
1db2224241 do not use mask in testnet cmd (#1451)
fix node ids
2018-04-11 20:53:33 +02:00
Anton Kaliaev
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
Anton Kaliaev
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
Thomas Corbière
ab00bf7c8b standardize PRNG access (#1411)
* replace math/rand with tmlibs equivalent.

* update tmlibs dependency
2018-04-11 11:38:30 +02:00
Bric3d
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
Vladislav Dmitriyev
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
Anton Kaliaev
e88f74bb9b remove wal_light setting
Closes #1428
2018-04-11 10:08:03 +02:00
suyuhuang
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
Thomas Corbière
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
Ethan Buchman
d93e177a69 Merge pull request #1446 from tendermint/1442-data-race-fix-attempt
fix data race
2018-04-10 16:49:36 +03:00
Anton Kaliaev
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
Anton Kaliaev
cca1dd8e3e removed excessive comment
Refs https://github.com/tendermint/tendermint/pull/1446#discussion_r180353446
2018-04-10 11:36:31 +02:00
Anton Kaliaev
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
Anton Kaliaev
609452958c [docs/specification/secure-p2p] add a note about config 2018-04-09 17:02:48 +02:00
Anton Kaliaev
c954fca376 gen_node_key cmd 2018-04-09 17:02:47 +02:00
Anton Kaliaev
9be16d56ba [docs] prefix IPs with node IDs
Refs #1429
2018-04-09 17:02:47 +02:00
Anton Kaliaev
2b732bc11a generate node_key when running tendermint init 2018-04-09 17:02:47 +02:00
Ethan Buchman
dcd00b0e68 update deps and changelog 2018-04-09 16:36:42 +03:00
Ethan Buchman
ff3f35c5f4 Merge pull request #1347 from tendermint/jae/aminoify
Convert Tendermint to use GoAmino
2018-04-09 16:24:38 +03:00
Ethan Buchman
93c4312cdd Merge pull request #1432 from tendermint/bucky/aminoify
Bucky/aminoify
2018-04-09 15:20:36 +03:00
Ethan Buchman
1a1e4e767b check max msg size in DecodeMessage 2018-04-09 15:18:47 +03:00
Ethan Buchman
bb1b249e8a types: lock block on MakePartSet 2018-04-09 15:04:59 +03:00
Ethan Buchman
c778d7f5d1 fix addresses 2018-04-07 23:13:41 +03:00
Ethan Buchman
bb9b12d67a add scripts/wire2amino.go 2018-04-07 22:04:28 +03:00
Ethan Buchman
767521ac52 update test/p2p/data for amino 2018-04-07 22:03:48 +03:00
Ethan Buchman
df9bf60b05 forgot Gopkg.lock 2018-04-07 20:59:13 +03:00
Ethan Buchman
466c3ab1c7 forgot node/wire.go 2018-04-07 19:53:29 +03:00
Ethan Buchman
c68d406195 fix tests 2018-04-07 19:47:19 +03:00
Ethan Buchman
02c0835e9b fixes post merge 2018-04-07 16:25:10 +03:00
Ethan Buchman
c170800fbd Merge branch 'develop' into jae/aminoify 2018-04-07 16:16:53 +03:00
Jae Kwon
7afe74a963 Update go-crypto to 0.6.1 and change config/toml.go privval address 2018-04-07 02:01:45 -07:00
Javed Khan
5d8767e656 p2p: don't use dial funcn in peerconfig 2018-04-07 12:51:51 +05:30
Javed Khan
54adb790f2 p2p: switch - reconnect only if persistent 2018-04-07 11:46:48 +05:30
Jae Kwon
02531ca5a3 Fix race testing (cont;) Bump version to 0.19.0 2018-04-06 17:06:46 -07:00
Jae Kwon
d24e4cb821 Fix race testing 2018-04-06 17:02:29 -07:00
Jae Kwon
fb64314d1c Review from Anton 2018-04-06 13:46:40 -07:00
Ethan Buchman
4930b61a38 Merge pull request #1431 from tendermint/release/v0.18.0
Release/v0.18.0
2018-04-06 23:19:09 +03:00
Ethan Buchman
9cc2cf362f changelog and version 2018-04-06 23:03:27 +03:00
Ethan Buchman
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
Anton Kaliaev
3d32474da8 make linter happy 2018-04-06 13:26:05 +02:00
Anton Kaliaev
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
Jae Kwon
32e1d195a0 Fix cmd and lite 2018-04-05 22:05:30 -07:00
Jae Kwon
3ca5292dc9 Fix rpc tests 2018-04-05 21:19:14 -07:00
Jae Kwon
c541d58d2f WIP: fix rpc/core 2018-04-05 16:07:29 -07:00
Jae Kwon
3037b5b7ca Fix rpc/lib/... 2018-04-05 15:45:11 -07:00
Ethan Buchman
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
Jae Kwon
e4492afbad Merge 2018-04-05 08:17:10 -07:00
Ethan Buchman
799beebd36 fix consensus tests 2018-04-05 17:54:26 +03:00
Jae Kwon
45ec5fd170 WIP consensus 2018-04-05 07:05:45 -07:00
Anton Kaliaev
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
Anton Kaliaev
d38a6cc7ea trim whitespace from elements of lists (like persistent_peers)
Refs #1380
2018-04-05 16:42:26 +03:00
Anton Kaliaev
7f6ee7a46b add a comment for NewSwitch 2018-04-05 15:27:47 +02:00
Anton Kaliaev
34b77fcad4 log error when we fail to add new address 2018-04-05 15:27:47 +02:00
Anton Kaliaev
3b3f45d49b use addrbook#AddOurAddress to store our address 2018-04-05 15:27:47 +02:00
Anton Kaliaev
3284a13fee add test
Refs #1275
2018-04-05 15:27:47 +02:00
Anton Kaliaev
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
Anton Kaliaev
3a672cb2a9 update changelog [ci skip] 2018-04-05 15:27:46 +02:00
Anton Kaliaev
4b8e342309 fix panic: lookup testing on 10.0.2.3:53: no such host 2018-04-05 15:27:46 +02:00
Anton Kaliaev
5a2fa71b03 use combination of IP and port, not just IP 2018-04-05 15:27:46 +02:00
Anton Kaliaev
9a57ef9cbf do not dial ourselves (ok, maybe just once)
Refs #1275
2018-04-05 15:27:46 +02:00
Ethan Buchman
59ca9bf480 update to tmlibs v0.8.1 2018-04-05 16:16:36 +03:00
Ethan Buchman
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
Ethan Buchman
0ae66f75ce Merge pull request #1420 from tendermint/1414-data-race
protect Record* peerStateStats functions by mutex
2018-04-05 15:53:15 +03:00
Jae Kwon
5d1c758730 Fix evidence 2018-04-05 05:43:23 -07:00
Jae Kwon
1b9323f105 Fix blockchain tests 2018-04-05 05:17:43 -07:00
Anton Kaliaev
cee7b5cb54 GetSelectionWithBias
Refs #1130
2018-04-05 12:00:16 +02:00
Anton Kaliaev
1585152341 https://github.com/tendermint/tendermint/pull/1128#discussion_r162799294
Refs #1130
2018-04-05 12:00:16 +02:00
Anton Kaliaev
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
Anton Kaliaev
904a3115a6 require addresses to have an ID by default
Refs #1228
2018-04-05 11:55:29 +02:00
Anton Kaliaev
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
Anton Kaliaev
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
Zaki Manian
f907113c19 Net_info should print the ID of peers (#1312) 2018-04-05 11:02:23 +02:00
Anton Kaliaev
140f962201 Merge pull request #1406 from tendermint/docker
Update dockerfile and readme
2018-04-05 10:57:19 +02:00
Ethan Buchman
c23d907f12 Merge pull request #1391 from tendermint/581-include-validator-power
Include validator power in /status
2018-04-05 11:18:45 +03:00
Anton Kaliaev
ed782e7508 include validator's voting power in /status
Refs #581
2018-04-04 11:34:59 +02:00
Anton Kaliaev
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
Anton Kaliaev
39a4963782 document funcs in validator_set.go 2018-04-04 10:42:35 +02:00
Anton Kaliaev
37ce6b195a ValidatorSet#GetByAddress: return -1 if no validator was found 2018-04-04 10:42:34 +02:00
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
5f548c7679 consensus: close pubsub channels. fixes #1372 2018-04-03 22:57:32 +03:00
Ethan Buchman
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
Ethan Buchman
39ff4d22e9 minor cleanup 2018-04-03 22:34:18 +03:00
Jae Kwon
196f8410ba WIP commit; Fix types/results_test 2018-04-03 07:03:08 -07:00
Anton Kaliaev
8462493cbf [rpc] fix subscribing using an abci.ResponseDeliverTx tag
Refs #1369
2018-04-03 15:53:13 +02:00
Anton Kaliaev
47b8bd1728 wrote a test for EventBus#PublishEventTx
Refs #1369
2018-04-03 15:53:13 +02:00
Jae Kwon
89cdde7f1e Fix state tests 2018-04-03 06:50:53 -07:00
Ethan Buchman
657fd671ea Merge pull request #1409 from tendermint/zach/docs/tm-monitor
docs: build updates
2018-04-03 15:24:55 +03:00
Zach Ramsay
315c475b79 docs: build updates
ref: https://github.com/tendermint/tools/pull/79
2018-04-03 04:48:40 -07:00
Javed Khan
5ef639fcbe p2p: persistent - redial if first dial fails
Fixes #1401
2018-04-03 09:27:06 +05:30
Anton Kaliaev
b800b4ec1d update docker readme 2018-04-02 16:57:25 +02:00
Anton Kaliaev
208ac32fa2 update Dockerfile to point to 0.17.1 release 2018-04-02 16:56:07 +02:00
Anton Kaliaev
641476d40f update docker to use alpine 3.7 2018-04-02 16:55:43 +02:00
Anton Kaliaev
491c8ab4c1 [rpc/lib] log cert and key files in StartHTTPAndTLSServer 2018-04-02 15:21:05 +02:00
Anton Kaliaev
5ef8a6e887 deprecate not fully formed addresses 2018-04-02 15:21:05 +02:00
Anton Kaliaev
d694d47d22 [rpc/lib] rename vars according to Go conventions 2018-04-02 15:21:05 +02:00
Zaki Manian
ecdc1b9bb0 Add a method for creating an https server (#1403) 2018-04-02 11:36:09 +02:00
Anton Kaliaev
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
Anton Kaliaev
5243e54641 [codecov] ignore docs, scripts and DOCKER dirs 2018-04-02 11:23:56 +02:00
Ethan Buchman
70e7454c21 comment out test_libs because of gcc dep in tmlibs 2018-04-02 11:23:56 +02:00
Thomas Corbière
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
Greg Szabo
eaee98ee1f CGO_ENABLED=0 added for static linking (#1396) 2018-04-01 19:54:48 +02:00
Jae Kwon
35a1d747b0 Fix mempool 2018-03-31 11:51:32 +02:00
Jae Kwon
34974e3932 Make types use Amino; Refactor PrivValidator* to FilePV/SocketPV 2018-03-31 00:18:43 +02:00
Alex Hernandez
575a46d9d4 fix typo on block header (#1387) 2018-03-29 11:28:29 +02:00
Ethan Buchman
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
Tomoya Ishizaki
ead9daf1ba Fix code style (#1362)
* cfg: Uniform style for method args and var names
2018-03-28 13:40:47 -04:00
Anton Kaliaev
22949e6dfd new tmlibs Parallel implementation 2018-03-28 19:13:08 +02:00
Anton Kaliaev
49986b05bc update tmlibs
Refs #1376
2018-03-28 19:12:52 +02:00
Vladislav Dmitriyev
2fa7af4614 [lite] fixed listen address (#1384) 2018-03-28 15:59:09 +02:00
Anton Kaliaev
2d857c4b1b add hash field to ResultTx (/tx and /tx_search endpoints) (#1374)
Refs #1367
2018-03-28 15:44:58 +02:00
Anton Kaliaev
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
Anton Kaliaev
4085c72496 sort /tx_search results by height by default
Refs #1366
2018-03-28 15:02:54 +02:00
Eugene Chung
34f5d439ee remove Heap.Update() call when setting Proposer field
In for loop of IncrementAccum(), Heap.Update() call is unnecessary when i == times - 1.
2018-03-28 12:58:53 +09:00
Ethan Buchman
6f9956990c Merge pull request #1377 from tendermint/release/0.17.1
Release/0.17.1
2018-03-27 11:24:48 -04:00
Ethan Buchman
9bf5862def types: fix genesis.AppStateJSON 2018-03-27 11:20:09 -04:00
Ethan Buchman
e1d98bb7f6 forgot bug fix in changelog 2018-03-27 10:06:30 -04:00
Ethan Buchman
e5cd006bce Merge pull request #1373 from tendermint/release/0.17.0
Release/0.17.0
2018-03-27 09:57:10 -04:00
Anton Kaliaev
58242e1b63 bump version one more time 2018-03-27 09:07:29 +02:00
Anton Kaliaev
4e86835163 update changelog for 0.17.0 release 2018-03-27 09:06:32 +02:00
Anton Kaliaev
ab4ac04c88 bump up the version 2018-03-26 22:07:07 +02:00
Anton Kaliaev
2c1887a635 update changelog 2018-03-26 22:06:58 +02:00
Anton Kaliaev
1c82281b77 make app_options -> app_state backwards compatible 2018-03-26 21:51:07 +02:00
Tomoya Ishizaki
43ac92b615 Changed to make line break easier to read (#1363) 2018-03-26 16:27:20 +02:00
Jae Kwon
901b456151 P2P now works with Amino 2018-03-26 06:40:02 +02:00
Emmanuel T Odeke
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
Emmanuel T Odeke
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
Emmanuel T Odeke
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
Ethan Buchman
e3337d764a Merge pull request #1354 from tendermint/bucky/dep
update dep
2018-03-24 12:14:56 -04:00
Anton Kaliaev
214817ed17 do not add peer to switch if it fails to start 2018-03-23 13:31:48 +01:00
Anton Kaliaev
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
Ethan Buchman
bbaad22982 update dep 2018-03-23 10:27:00 +01:00
Anton Kaliaev
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
Zach
6545a21369 docs/examples: update quick start guide (#1351) 2018-03-22 08:58:02 +01:00
Zarko Milosevic
416f03c05b Add light client spec 2018-03-21 10:00:18 +01:00
Jae Kwon
ced74251e9 maxPacketMsg -> packetMsgMax... 2018-03-21 02:47:38 +01:00
Jae Kwon
6c345f9fa2 First stab: p2p/conn 2018-03-21 02:27:10 +01:00
Ethan Buchman
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
Alexander Simmerl
79315efd1f Merge pull request #1341 from EugeneChung/develop
Remove unnecessary bytes.Compare() call
2018-03-20 16:27:06 +01:00
Eugene Chung
a61130aebb Remove unnecessary bytes.Compare() call 2018-03-20 23:43:18 +09:00
Alexander Simmerl
5a51a0ba06 Merge pull request #1337 from tendermint/1296-follow-up
Follow up for /health endpoint
2018-03-20 10:36:47 +01:00
Ethan Buchman
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
Ethan Buchman
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
Alexander Simmerl
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
Zarko Milosevic
5a79b3d74a Improve the spec to make explicit median computation based on voting power 2018-03-19 19:10:02 +01:00
Anton Kaliaev
460599ef75 fix comment 2018-03-19 20:01:43 +03:00
Anton Kaliaev
830bb72d6f add Health method to clients
Refs #1296
2018-03-19 20:01:43 +03:00
Anton Kaliaev
b11c26cc1c update CHANGELOG 2018-03-19 19:53:28 +03:00
Constantine
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
Ethan Buchman
20b198681b Merge pull request #1328 from tendermint/bucky/add-vote-readability
addVote readability
2018-03-19 12:24:28 +01:00
Ethan Buchman
2bf106a1b3 Merge pull request #1333 from tendermint/1244-follow-up
consensus: fix tracking for MarkGood
2018-03-19 12:19:16 +01:00
Anton Kaliaev
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
Anton Kaliaev
d8b08cd943 return back panic in peer#onReceive
Refs #1317
2018-03-19 13:19:05 +03:00
Anton Kaliaev
ab59f64f57 test we record votes and block parts
Refs #1317
2018-03-19 13:17:11 +03:00
Anton Kaliaev
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
Anton Kaliaev
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
Anton Kaliaev
5fab8e404d replace magic number with blocksToContributeToBecomeGoodPeer const
Refs #1317
2018-03-19 13:16:56 +03:00
Anton Kaliaev
701df09971 do not use keywords
Refs #1317
2018-03-19 13:16:02 +03:00
Ethan Buchman
d350da3135 config: fix private_peer_ids 2018-03-18 23:55:44 +01:00
Ethan Buchman
ab7dea4f20 consensus: return from errors sooner in addVote 2018-03-18 23:09:04 +01:00
Ethan Buchman
b297efb532 consensus: return from go-routine in test 2018-03-18 23:05:04 +01:00
Ethan Buchman
eaabdb5cac Merge pull request #1282 from tendermint/1126-private-peers
private peers
2018-03-18 22:53:57 +01:00
racin
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
Ethan Buchman
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
Emmanuel T Odeke
7cb3188fbc testnet cmd: ensure config dir exists. closes #1290 2018-03-16 14:26:43 +01:00
Alexander Simmerl
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
Ethan Buchman
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
Anton Kaliaev
86ddf17db0 add a todo
Refs #1281
2018-03-15 11:58:20 +04:00
Anton Kaliaev
a655500047 fix copy-pasted comment [ci skip] 2018-03-15 11:58:20 +04:00
Anton Kaliaev
714f885dac mark peer as good if it contributed enough votes or block parts
Refs #1147
2018-03-15 11:58:20 +04:00
Anton Kaliaev
b0d8f552c5 return err if peer has sent a vote that does not match our round 2018-03-15 11:58:20 +04:00
Anton Kaliaev
63cb69cb96 comment out ErrAddingVote because it breaks byzantine_test 2018-03-15 11:58:20 +04:00
Anton Kaliaev
266974cb59 stop peer if it sends invalid vote 2018-03-15 11:58:20 +04:00
Anton Kaliaev
bcf54b0aa3 PanicSanity is deprecated 2018-03-15 11:58:20 +04:00
Anton Kaliaev
d86855ad7a stop peer if it sends us msg with unknown channel 2018-03-15 11:58:20 +04:00
Anton Kaliaev
d0c67bbe16 stop peer if evidence is not valid 2018-03-15 11:58:20 +04:00
Anton Kaliaev
4242352852 stop peer on decoding error 2018-03-15 11:58:19 +04:00
Anton Kaliaev
f299689573 return back defaultChannelCapacity 2018-03-15 11:58:19 +04:00
Anton Kaliaev
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
Anton Kaliaev
0c7e871ef0 [blockchain] replace timeoutsCh with more abstract errorsCh 2018-03-15 11:58:19 +04:00
Anton Kaliaev
87ce804b4a cmn.PanicSanity is deprecated 2018-03-15 11:58:19 +04:00
Anton Kaliaev
2a258a2c3f revert removing private peers from persistent 2018-03-15 11:55:30 +04:00
Anton Kaliaev
a40518c7da revert adding dial_peers's private flag 2018-03-15 11:55:30 +04:00
Anton Kaliaev
31deaa4a79 fix broken merge 2018-03-15 11:55:30 +04:00
Anton Kaliaev
736ea055a8 add a test for pex reactor 2018-03-15 11:55:30 +04:00
Anton Kaliaev
a39aec0bae rename private_peers to private_peer_ids to distinguish from peers 2018-03-15 11:55:30 +04:00
Anton Kaliaev
8bef3eb1f4 private peers
Refs #1126
2018-03-15 11:55:29 +04:00
Ethan Buchman
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
Anton Kaliaev
76e1dd41e4 fix Makefile's .PHONY 2018-03-14 21:42:35 +04:00
Anton Kaliaev
e39187a063 add go-amino as source for go-wire 2018-03-14 21:42:17 +04:00
Ethan Buchman
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
Emmanuel T Odeke
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
Ethan Buchman
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
Anton Kaliaev
fc5b0471d9 use time.Since 2018-03-11 14:13:34 +04:00
Anton Kaliaev
264bce4ddd skip dialing based on last time dialed 2018-03-11 14:00:49 +04:00
Anton Kaliaev
0f41570c80 fixes from bucky's review 2018-03-11 13:22:37 +04:00
Emmanuel T Odeke
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
Anton Kaliaev
f85c8896d9 test pex_reactor's dialPeer 2018-03-09 16:23:52 +04:00
Anton Kaliaev
f0d4f56327 refactor pex_reactor tests 2018-03-09 16:02:24 +04:00
Anton Kaliaev
3d5c05e4e6 Merge pull request #1293 from tendermint/update-template
add 2 more points to ISSUE_TEMPLATE
2018-03-09 15:15:34 +04:00
Anton Kaliaev
018da09f14 do not run complete test suite on make
bad dev experience
2018-03-08 18:55:14 +04:00
Anton Kaliaev
60a64af28d add 2 more points to ISSUE_TEMPLATE
Refs #1291
2018-03-08 18:53:11 +04:00
Zach
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
Anton Kaliaev
1941b5c769 fixes from @xla's review 2018-03-08 16:31:44 +04:00
Anton Kaliaev
21e2c41c6b exponential backoff for addrs in the address book
Refs #1125
2018-03-08 14:04:26 +04:00
Alexander Simmerl
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
Ethan Buchman
2ce57a65ff Merge pull request #1284 from tendermint/feature/xla-follow-priv-val
Follow-ups to PrivValidator
2018-03-06 23:37:10 +01:00
Alexander Simmerl
2aa77025c3 Fix typo 2018-03-06 19:56:31 +01:00
Alexander Simmerl
8e1856a90a Use builtin panic 2018-03-06 19:56:31 +01:00
Alexander Simmerl
ca619c80b6 Stop privVal socket client on node shutdown 2018-03-06 19:56:30 +01:00
Alexander Simmerl
25ff699425 Improve method docs 2018-03-06 19:55:26 +01:00
Alexander Simmerl
879b4c0a2c Use common method to determine file existence 2018-03-06 19:55:26 +01:00
Ethan Buchman
45d07a3d0b Merge pull request #1283 from tendermint/feature/xla-run-integration-release
Speed up CircleCI builds
2018-03-06 19:38:08 +01:00
Admir Sabanovic
788354d81e fix typo (#1285) 2018-03-06 20:44:13 +04:00
Alexander Simmerl
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
Anton Kaliaev
8d81a259c7 Merge pull request #1280 from tendermint/zach/explain-determinism
docs: add 'On Determinism'
2018-03-06 13:44:00 +04:00
Zach Ramsay
3019761204 docs: add document 'On Determinism'
closes https://github.com/tendermint/abci/issues/56
2018-03-06 15:19:59 +08:00
Anton Kaliaev
6120a4c5e4 Merge pull request #1256 from tendermint/feature/more-priv-val
PrivValidatorAddr -> PrivValidatorListenAddr. Update ADR008
2018-03-05 21:48:16 +04:00
Alexander Simmerl
533ed2a876 adr: Amend decisions for PrivValidator 2018-03-05 17:38:05 +01:00
Ethan Buchman
d4e4055d57 PrivValidatorAddr -> PrivValidatorListenAddr. Update ADR008 2018-03-05 17:11:43 +01:00
Alexander Simmerl
ee51ad8e29 Make RPC handler protocol agnostic (#1276) 2018-03-05 19:59:04 +04:00
Zach
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
Anton Kaliaev
3d88612690 Merge pull request #1274 from tendermint/codecov
Codecov
2018-03-05 15:54:33 +04:00
Anton Kaliaev
630d54c95a return back threshold and ignore sections 2018-03-05 15:16:24 +04:00
Ethan Buchman
3cedd8cf07 Merge pull request #1265 from tendermint/bucky/new-wire-api
Bucky/new wire api
2018-03-02 10:56:24 -05:00
Ethan Buchman
929f326dd2 update dep 2018-03-02 10:59:10 -05:00
Ethan Buchman
ff8c648c23 types: uncomment some tests 2018-03-02 09:26:37 -05:00
Ethan Buchman
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
Alexander Simmerl
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
Ethan Buchman
c394eef7b8 types: TestValidatorSetVerifyCommit 2018-03-02 04:21:23 -05:00
Ethan Buchman
f9921ae362 types/validator_set_test: move funcs around 2018-03-02 03:52:44 -05:00
Ethan Frey
fff0c6cd8e Add app_state from genesis file in InitChain message 2018-03-02 03:46:04 -05:00
Ethan Buchman
59872bf335 update dep for new go-wire API 2018-03-02 02:28:53 -05:00
Ethan Buchman
656854186c state: fix txResult issue with UnmarshalBinary into ptr 2018-03-02 02:28:17 -05:00
Ethan Buchman
6596bff8ec types: bring back json.Marshal/Unmarshal for genesis/priv_val 2018-03-02 02:09:28 -05:00
Ethan Buchman
eaafd9d61c state: builds 2018-03-02 01:51:27 -05:00
Ethan Buchman
5378bfc5c7 types.SignBytes -> o.SignBytes 2018-03-02 01:50:17 -05:00
Ethan Buchman
abeeeeb611 types: fix validator_set_test issue with UnmarshalBinary into ptr 2018-03-02 01:49:59 -05:00
Ethan Buchman
ca3655a409 types: p2pID -> P2PID 2018-03-02 01:42:56 -05:00
Ethan Buchman
6cf5100645 types: working on tests... 2018-03-02 01:34:23 -05:00
Ethan Buchman
51628aea08 types: revert to old wire. builds 2018-03-02 01:33:38 -05:00
Ethan Buchman
3395f5fb0e types: builds 2018-03-02 01:28:38 -05:00
Ethan Buchman
d2cd079541 types: tests build 2018-03-02 01:28:21 -05:00
Ethan Buchman
fc35e3b8c5 wire: no codec yet 2018-03-02 01:27:52 -05:00
Ethan Buchman
085b4f5f2e add wire pkg with global codec 2018-03-02 01:26:38 -05:00
Ethan Buchman
fd58645dd2 types: remove dep on p2p 2018-03-02 01:26:03 -05:00
Ethan Buchman
200787ede2 types: update for new go-wire. WriteSignBytes -> SignBytes 2018-03-02 01:25:54 -05:00
Ethan Buchman
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
Anton Kaliaev
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
Zarko Milosevic
d4e93a6de3 Separate ValidBlock rule from unlocking rule 2018-03-01 11:42:22 +01:00
Zarko Milosevic
4670857c15 Add support for ValidBlock mechanism for the simplest case 2018-03-01 11:42:22 +01:00
Anton Kaliaev
e8d8aedd1f update changelog 2018-03-01 12:00:09 +04:00
Anton Kaliaev
87372da730 return back dummy & persistent_dummy as options for proxy_app 2018-03-01 11:54:08 +04:00
Anton Kaliaev
3b40b62d04 Merge pull request #1198 from tendermint/feature/genesisrawjson
SDK: AppOptions -> AppState
2018-03-01 00:55:13 +04:00
Anton Kaliaev
c41cbf2a07 add missing golang.org/x/net/netutil package 2018-02-28 23:44:18 +04:00
Anton Kaliaev
1a3faa8db1 add app_state field to docs 2018-02-28 23:44:10 +04:00
Anton Kaliaev
4ce79baac7 rename app_options to app_state in genesis_test 2018-02-28 23:44:10 +04:00
Anton Kaliaev
056b70b4ce update changelog 2018-02-28 23:44:10 +04:00
rigelrozanski
4806b3b9bf AppOptions -> AppStateJSON 2018-02-28 23:44:10 +04:00
Ethan Buchman
2a8f0000b2 Merge pull request #1250 from tendermint/ditch-glide
Ditch glide
2018-02-28 09:52:12 -05:00
Ethan Buchman
dd2d846c02 Merge pull request #1203 from tendermint/feature/priv_val
types/priv_validator package
2018-02-28 09:27:03 -05:00
Anton Kaliaev
2ae87eee4e style fixes from @xla 2018-02-28 12:24:26 +04:00
use-n-delete
4be23027ed adding recipe for minimalistic deps analysis (#1218) 2018-02-28 11:23:31 +04:00
Anton Kaliaev
c19bbb2403 switch back to parsing .lock file 2018-02-28 11:15:40 +04:00
Ethan Buchman
edb871f514 Merge pull request #1237 from tendermint/feature/priv_val_socket_client
privVal: Integrate socket client
2018-02-28 00:57:51 -05:00
Ethan Buchman
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
Ethan Buchman
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
Anton Kaliaev
66354de219 cd into tendermint before calling dep status 2018-02-27 18:47:53 +04:00
Alexander Simmerl
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
Anton Kaliaev
0821384ac6 update abci version 2018-02-27 18:34:32 +04:00
Anton Kaliaev
e01650f21d fix Dockerfile.develop 2018-02-27 18:02:40 +04:00
Anton Kaliaev
8dd06cf197 ditch glide 2018-02-27 18:02:40 +04:00
Anton Kaliaev
93732b4c1e remove old network tests
Refs #1249
2018-02-27 18:02:25 +04:00
Zach
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
Zaki Manian
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
Ethan Buchman
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
Alexander Simmerl
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
Ethan Buchman
2fd023a239 remove accidental binary 2018-02-21 00:04:53 -05:00
Ethan Buchman
c8a2bdf78b Merge pull request #1225 from tendermint/release-v0.16.0
Release v0.16.0
2018-02-20 23:23:48 -05:00
Zach Ramsay
3cd604562c RequestInitChain needs genesisBytes 2018-02-21 03:43:47 +00:00
Zach Ramsay
7c6c0dba53 glide update 2018-02-21 03:32:02 +00:00
Ethan Buchman
ec2f3f49ef changelog date and version 2018-02-19 17:35:46 -05:00
Ethan Buchman
8bba7c64bc update version and changelog [ci skip] 2018-02-19 17:33:48 -05:00
Ethan Buchman
ffd2483e67 Merge pull request #1204 from tendermint/feature/priv_val_sockets
Feature/priv val sockets
2018-02-19 16:06:07 -05:00
Ethan Buchman
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
Anton Kaliaev
0ae0155cba restore mempool memory leak tests 2018-02-19 15:34:33 -05:00
Ethan Buchman
f4feb7703b fix appHash log. closes #1207 2018-02-19 15:32:09 -05:00
Alexander Simmerl
a14aab67de Integrate PrivValidator socket server 2018-02-19 19:20:01 +01:00
Alexander Simmerl
106d804357 Correct config description 2018-02-14 02:51:05 +01:00
Alexander Simmerl
a1020307a0 Clean up flags 2018-02-14 02:41:16 +01:00
Alexander Simmerl
6c70b4ce05 Apply connection deadline consistently 2018-02-14 02:25:17 +01:00
Alexander Simmerl
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
Alexander Simmerl
82b1a34a36 Separate connect logic
* break out connect functionality out of OnStart
* introduce max retries
2018-02-13 19:08:21 +01:00
Ethan Buchman
0e68638af3 update glide abci/tmlibs to develop 2018-02-12 19:13:36 -05:00
Ethan Buchman
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
Anton Kaliaev
fc585bcdec do not block when writing to pongTimeoutCh
Refs #1205
2018-02-12 17:04:07 +04:00
Anton Kaliaev
2a24ae90c1 fixes from Jae's review
1. remove pointer
2. add Quit() method to Service interface
2018-02-12 14:32:09 +04:00
Ethan Buchman
8da2a6a147 types/priv_validator: fixes for latest p2p and cmn 2018-02-09 17:24:30 -05:00
Alexander Simmerl
7d71e702d8 Integrate privVal client with node secret 2018-02-09 16:54:43 -05:00
Alexander Simmerl
38d18ca11a Harden tests 2018-02-09 16:53:17 -05:00
Alexander Simmerl
32d9563a15 Format and consolidate 2018-02-09 16:53:17 -05:00
Alexander Simmerl
18f7e52562 Use secret connection 2018-02-09 16:53:17 -05:00
Alexander Simmerl
fec541373d Correct server protocol 2018-02-09 16:53:17 -05:00
Alexander Simmerl
ff600e9aa0 wip: check error of wire read 2018-02-09 16:53:17 -05:00
Alexander Simmerl
a49357b19e wip: Avoid underscore in var name 2018-02-09 16:53:17 -05:00
Alexander Simmerl
4b997c29ee wip: fix nil pointer deference 2018-02-09 16:53:17 -05:00
Alexander Simmerl
d321839669 wip: fix code block in ADR 2018-02-09 16:53:17 -05:00
Alexander Simmerl
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
Ethan Buchman
23eb84db35 wip: priv val via sockets 2018-02-09 16:52:58 -05:00
Ethan Buchman
bef91ea7fe adr-008-priv-validator 2018-02-09 16:52:05 -05:00
Ethan Buchman
459633fb4c types/priv_validator 2018-02-09 16:38:23 -05:00
Ethan Buchman
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
Ethan Buchman
2d10c8f15b Merge pull request #1095 from tendermint/804-p2p-issues
[p2p] Pong Timeout
2018-02-09 14:38:24 -05:00
Anton Kaliaev
106cdb74e5 do not enforce 1/3 validator power change
leave it to the app

Refs #1022
2018-02-09 23:30:04 +04:00
Anton Kaliaev
22b038810a do not block in recvRoutine 2018-02-09 23:03:26 +04:00
Anton Kaliaev
45750e1b29 fix race by sending signal instead of stopping pongTimer 2018-02-09 21:32:29 +04:00
Anton Kaliaev
26419fba28 refactor code plus add one more test
* extract stopPongTimer method
* TestMConnectionMultiplePings
2018-02-09 21:32:29 +04:00
Anton Kaliaev
ac0123d249 drain pongTimeoutCh and pongTimer's channel to prevent leaks 2018-02-09 21:32:29 +04:00
Anton Kaliaev
f4ff66de30 rewrite pong timer to use time.AfterFunc 2018-02-09 21:32:29 +04:00
Anton Kaliaev
747b73cb95 fix merge conflicts 2018-02-09 21:32:29 +04:00
Anton Kaliaev
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
Anton Kaliaev
3ae738f453 increase timeouts 2018-02-09 21:32:29 +04:00
Anton Kaliaev
d14d4a2527 remove TryBroadcast 2018-02-09 21:32:29 +04:00
Anton Kaliaev
860da464df remove weird concurrency testing 2018-02-09 21:32:28 +04:00
Anton Kaliaev
4e2000abfe control order by sending msgs from one goroutine 2018-02-09 21:32:28 +04:00
Anton Kaliaev
5834a59816 read ping 2018-02-09 21:32:28 +04:00
Anton Kaliaev
b28b76ddf7 rename pingTimeout to pingInterval, pongTimer is now time.Timer 2018-02-09 21:32:28 +04:00
zbo14
91e4f4b786 ping/pong timeout in config 2018-02-09 21:32:28 +04:00
zbo14
9b554fb2c4 switch test modification 2018-02-09 21:32:28 +04:00
zbo14
f97ead4f5f prep for merge 2018-02-09 21:32:28 +04:00
zbo14
5af22d6ee6 remove SwitchEventNewPeer, SwitchEventDonePeer 2018-02-09 21:32:28 +04:00
zbo14
1d16df6a92 add test, TrySend in broadcast 2018-02-09 21:32:27 +04:00
Ethan Buchman
e7bc946760 Merge pull request #1200 from tendermint/update-deps
Update tmlibs & protobuf deps
2018-02-09 11:00:43 -05:00
Ethan Buchman
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
Anton Kaliaev
2f8372d629 update protobuf 2018-02-09 13:58:36 +04:00
Anton Kaliaev
d84e4effce update tmlibs 2018-02-09 13:47:51 +04:00
Anton Kaliaev
0c1b91b762 revert back curRate != 0 2018-02-09 13:02:44 +04:00
Anton Kaliaev
c8990d06d9 remove curRate != 0 2018-02-09 12:01:13 +04:00
Anton Kaliaev
b0a55882b2 lower the minRecvRate
See https://github.com/tendermint/tendermint/issues/1177#issuecomment-363720118
2018-02-09 12:01:12 +04:00
Anton Kaliaev
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
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
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
Anton Kaliaev
cf1f483526 add seed_mode flag (--p2p.seed_mode) 2018-02-08 17:20:55 +04:00
Anton Kaliaev
3f9aa8d8fa document that msgBytes in p2p/connection change 2018-02-08 13:25:26 +04:00
Anton Kaliaev
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
Anton Kaliaev
2b2c233977 write docs for Reactor interface 2018-02-08 13:07:40 +04:00
Ethan Buchman
7640e6a29f add some p2p TODOs 2018-02-08 12:46:04 +04:00
Anton Kaliaev
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
Ethan Buchman
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
Anton Kaliaev
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
Emmanuel Odeke
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
Luke Schoen
f37c502fd8 Update getting-started.rst with Python 3 example 2018-02-06 16:00:51 +11:00
Anton Kaliaev
945b0e6eca cleanup glide.yaml 2018-02-05 22:53:44 +04:00
Anton Kaliaev
84a0a1987c comment out tests for now
https://github.com/tendermint/tendermint/pull/1173#issuecomment-363173047
2018-02-05 22:26:14 +04:00
Anton Kaliaev
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
Anton Kaliaev
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
Ethan Buchman
bf84e82577 Merge pull request #1184 from tendermint/sdk2-tmlibs-abci
Updates for tmlibs and abci (sdk2)
2018-02-03 10:45:54 -05:00
Ethan Buchman
abca9a2d61 woops - bring back glide.lock file 2018-02-03 03:59:16 -05:00
Ethan Buchman
d34286c421 minor fixes - tests pass 2018-02-03 03:54:49 -05:00
Anton Kaliaev
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
Ethan Buchman
e7747f7d66 it compiles 2018-02-03 03:52:17 -05:00
Ethan Buchman
7a5060dc52 replace data.Bytes with cmn.HexBytes 2018-02-03 03:47:01 -05:00
Ethan Buchman
426379dc47 remove use of wire/nowriter 2018-02-03 03:39:14 -05:00
Ethan Buchman
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
Ethan Buchman
4e3488c677 update types 2018-02-03 03:23:10 -05:00
Ethan Buchman
061ad355bb update glide 2018-02-03 03:22:56 -05:00
Ethan Buchman
2679b7554b lite: comment out iavl code - TODO #1183 2018-02-03 03:02:49 -05:00
Ethan Buchman
62c9cad484 Merge pull request #1180 from tendermint/1146-add-BFT-time-spec
Add BFT time spec
2018-02-01 16:38:05 -05:00
Zarko Milosevic
4cbdbbaac9 Add BFT time spec 2018-02-01 15:22:08 +01:00
Emmanuel Odeke
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
Zach Ramsay
e8d0960cef nolint 2018-01-31 20:52:12 -07:00
Emmanuel Odeke
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
Adrian Brink
7790ae9e6f Fix spelling mistake 2018-01-31 20:52:12 -07:00
Emmanuel Odeke
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
Emmanuel Odeke
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
Ethan Buchman
2919bc3f7f Merge pull request #1178 from tendermint/nice-err-msg
improve error message
2018-01-31 21:32:58 -05:00
Zach Ramsay
1c01671ec6 improve vague error msg, closes #1158 2018-01-31 17:44:19 +00:00
Ethan Buchman
fe632ea32a spec: minor fixes 2018-01-26 17:26:33 -05:00
Zach Ramsay
5b368252ac spec: more fixes 2018-01-26 17:26:33 -05:00
Zach Ramsay
8cca953590 spec: remove notes, see #1152 2018-01-26 17:26:33 -05:00
Zach Ramsay
4b4a2029c4 spec: typos & other fixes 2018-01-26 17:26:33 -05:00
Ethan Buchman
6aa85357b6 Merge pull request #1160 from shapeshed/patch-1
Fix documentation typos
2018-01-26 17:17:43 -05:00
Ethan Buchman
eae62ec09b Merge branch 'develop' into patch-1 2018-01-26 17:17:28 -05:00
Ethan Buchman
18d96266bc Merge pull request #1140 from tendermint/feature/vagrant
Fix Vagrantfile
2018-01-26 17:12:06 -05:00
George Ornbo
4529fd6787 Fix documentation typos 2018-01-26 14:44:48 +00:00
Ethan Buchman
4a99a2a07d update contributing.md 2018-01-26 01:18:33 -05:00
Adrian Brink
4b63b3aa0b Switch to correct directory in Vagrant 2018-01-26 01:16:07 -05:00
Adrian Brink
fc860c3a07 Final Vagrantfile 2018-01-26 01:16:07 -05:00
Adrian Brink
2f147ec000 Remove upgrade step 2018-01-26 01:16:07 -05:00
Adrian Brink
0a7a190cd1 Fix vagrantfile
If you get an error, please run `vagrant box update`.
2018-01-26 01:16:07 -05:00
Ethan Buchman
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
Ethan Buchman
baff4bd8cc p2p/conn: better handling for some stop conditions 2018-01-25 02:11:16 -05:00
Ethan Buchman
fb109db33d update changelog 2018-01-25 02:10:01 -05:00
Ethan Buchman
2f5971532e Merge pull request #1154 from tendermint/fix/consensus-tests
consensus: fix SetLogger in tests
2018-01-25 02:07:20 -05:00
Ethan Buchman
ab13806276 consensus: print go routines in failed test 2018-01-25 01:22:53 -05:00
Ethan Buchman
3ae26bd6e6 consensus: fix SetLogger in tests 2018-01-24 23:34:57 -05:00
Ethan Buchman
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
Ethan Buchman
b6eb275b22 p2p: fix break in double loop 2018-01-24 14:27:37 -05:00
Ethan Buchman
57cc8ab977 Merge pull request #1143 from tendermint/1091-race-condition
call FlushSync before calling CommitSync
2018-01-24 14:22:43 -05:00
Ethan Buchman
99034904f8 p2p: fix tests for required channels 2018-01-23 23:45:51 -05:00
Ethan Buchman
a0ffcbcee4 Merge pull request #1137 from tendermint/docs-consolidate
WIP: docs consolidation
2018-01-23 23:45:20 -05:00
Ethan Buchman
260affd037 docs consolidation 2018-01-23 23:46:28 -05:00
Ethan Buchman
d7b1b8d3d5 Merge pull request #1129 from tendermint/addrbook
p2p: bust up into sub dirs
2018-01-23 23:10:50 -05:00
Ethan Buchman
50129ad8ac p2p: add Channels to NodeInfo and don't send for unknown channels 2018-01-23 22:43:56 -05:00
Ethan Buchman
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
Ethan Buchman
4051391039 blockchain: test wip for hard to test functionality [ci skip] 2018-01-23 22:27:33 -05:00
Ethan Buchman
8f3bd3f209 p2p: addrBook.Save() on DialPeersAsync 2018-01-23 22:25:39 -05:00
Ethan Buchman
85816877c6 config: fix addrbook path to go in config 2018-01-23 22:21:17 -05:00
Ethan Buchman
87087b8acd consensus: minor cosmetic 2018-01-23 21:41:13 -05:00
Ethan Buchman
775bb85efb p2p/pex: wait to connect to all peers in reactor test 2018-01-23 21:30:53 -05:00
Ethan Buchman
21ce5856b3 p2p: notes about ListenAddr 2018-01-23 21:26:19 -05:00
Ethan Buchman
f5226e0008 Merge pull request #1144 from tendermint/create-logs-tarball
mercy for developers with slow Internet
2018-01-23 12:47:45 -05:00
Anton Kaliaev
a745fe2eed mercy for developers with slow Internet 2018-01-23 20:37:38 +04:00
Anton Kaliaev
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
Ethan Buchman
6a5818e107 Merge pull request #1138 from tendermint/small-fix
Small fix in example
2018-01-22 17:27:35 -05:00
Zarko Milosevic
dfdfd6c98e Small fix in example 2018-01-22 13:10:54 +01:00
Ethan Buchman
3090b05eb4 p2p: use conn.Close when peer is nil 2018-01-21 16:26:59 -05:00
Ethan Buchman
ee674f919f StopPeerForError in blockchain and consensus 2018-01-21 13:32:04 -05:00
Ethan Buchman
813bb6af96 Merge pull request #1092 from tendermint/add-consensus-reactor-doc
Add consensus reactor doc
2018-01-21 12:40:28 -05:00
Ethan Buchman
aecbff725f Merge pull request #1082 from tendermint/document-proposer-selection
Document proposer selection procedure
2018-01-21 12:39:43 -05:00
Ethan Buchman
6679fef2be Merge pull request #1056 from tendermint/feature/mempool-spec
WIP: Mempool specification
2018-01-21 12:39:10 -05:00
Ethan Buchman
c070ed056a Merge pull request #1051 from tendermint/feature/blockchain_reactor_docs
docs: Blockchain Reactor Documentation
2018-01-21 12:38:32 -05:00
Ethan Buchman
2c6ed302b7 minor changes [ci skip] 2018-01-21 12:36:46 -05:00
Adrian Brink
0eb85161aa More specification 2018-01-21 12:35:09 -05:00
Adrian Brink
940145b368 Bullet points for reactor and poolRoutine 2018-01-21 12:32:45 -05:00
Adrian Brink
a30315276b Formatting and documentation 2018-01-21 12:32:23 -05:00
Adrian Brink
6366eb9d99 Cleanup build and structure 2018-01-21 12:31:14 -05:00
Ethan Buchman
44e967184a p2p: tmconn->conn and types->p2p 2018-01-21 00:34:41 -05:00
Ethan Buchman
2ec425ae4b Merge pull request #1128 from tendermint/862-seed-crawler-mode
seed crawler mode
2018-01-20 23:35:26 -05:00
Ethan Buchman
0d7d16005a fixes 2018-01-20 21:44:30 -05:00
Ethan Buchman
5b5cbaa66a p2p: use sub dirs 2018-01-20 21:35:37 -05:00
Ethan Buchman
03550c7076 wip addrbook 2018-01-20 21:33:43 -05:00
Ethan Buchman
930fde056a p2p: add back lost func 2018-01-20 21:28:00 -05:00
Ethan Buchman
8d758560d8 p2p/trustmetric: non-deterministic test 2018-01-20 21:24:22 -05:00
Ethan Buchman
7b87cdaed8 p2p: seed disconnects after sending addrs 2018-01-20 21:24:22 -05:00
Ethan Buchman
c2f97e6454 p2p: seed mode fixes from rebase and review 2018-01-20 21:24:22 -05:00
Ethan Buchman
88eb3e7af0 some minor renames 2018-01-20 21:24:20 -05:00
caffix
949211a137 added a test for PEX reactor seed mode 2018-01-20 21:23:48 -05:00
Ethan Buchman
39d8da3536 docs: update getting started [ci skip] 2018-01-20 21:21:50 -05:00
Ethan Buchman
ae27e85bf7 add warnings about new spec 2018-01-20 21:20:15 -05:00
Ethan Buchman
f2d19162d2 fixes from caffix review 2018-01-20 21:20:09 -05:00
Zarko Milosevic
d36e118bf6 Add Consensus reactor spec 2018-01-19 19:57:08 +01:00
Ethan Buchman
02c1aef48b Merge pull request #1121 from tendermint/consensus-tests
Consensus tests
2018-01-19 12:50:32 -05:00
Ethan Buchman
6f3d9b4be3 fix race 2018-01-19 01:36:52 -05:00
Ethan Buchman
f06cc6630b mempool: cfg.CacheSize and expose InitWAL 2018-01-19 01:03:03 -05:00
Ethan Buchman
8171628ee5 make tests run faster 2018-01-19 00:59:09 -05:00
Ethan Buchman
1cb76625d3 consensus: rename test funcs 2018-01-19 00:59:09 -05:00
Ethan Buchman
ebeadfc57e dont run metalinter 2018-01-19 00:58:54 -05:00
Ethan Buchman
cca597a9c0 fix and test config file 2018-01-19 00:08:19 -05:00
Ethan Buchman
940db715f4 Merge pull request #1104 from tendermint/p2p-consolidate
WIP: P2P consolidate
2018-01-18 19:00:35 -05:00
Ethan Buchman
ec2b038493 Merge pull request #1103 from tendermint/1100-document-event-subscriptions
document event subscriptions
2018-01-18 19:00:01 -05:00
Ethan Buchman
ba0cb4f10e Merge pull request #1115 from tendermint/docs-tx-format
document tx formats
2018-01-18 18:57:23 -05:00
Ethan Buchman
e764a180d8 docs: fix tx formats [ci skip] 2018-01-18 18:58:33 -05:00
Ethan Buchman
bc19e7843c Merge branch 'develop' into p2p-consolidate 2018-01-18 18:30:37 -05:00
Ethan Buchman
f57f97c4bd fix bash tests 2018-01-18 17:40:12 -05:00
Ethan Buchman
b32474bb1a Merge pull request #1116 from tendermint/feature/prs
Create PULL_REQUEST_TEMPLATE.md
2018-01-18 13:52:18 -05:00
Adrian Brink
0a20e8f268 Create PULL_REQUEST_TEMPLATE.md 2018-01-18 13:53:18 -05:00
Zach Ramsay
9d4d939b89 docs: tx formats: closes #1083, #536 2018-01-18 15:37:56 +00:00
Ethan Buchman
c1e6e73bb1 Merge pull request #1108 from tendermint/zramsay-patch-1
Update p2p README
2018-01-15 10:31:31 -05:00
Ethan Buchman
620c957a44 fix test 2018-01-14 13:24:43 -05:00
Ethan Buchman
64ce7eef16 Merge pull request #1107 from tendermint/p2p-pex-abuse
better abuse handling in pex
2018-01-14 13:03:02 -05:00
Ethan Buchman
fc7915ab4c fixes from review 2018-01-14 13:03:57 -05:00
Zach Ramsay
26aaa283a9 p2p: remove deprecated Dockerfile 2018-01-14 13:51:28 +00:00
Zach
a29c67563c Update p2p README, closes #1102 2018-01-14 13:50:34 +00:00
Ethan Buchman
17f7a9b510 improve seed dialing logic 2018-01-14 03:56:15 -05:00
Ethan Buchman
3df5fd21cd better abuse handling in pex 2018-01-14 03:22:01 -05:00
Ethan Buchman
99076f1942 Merge pull request #1105 from tendermint/p2p-switch
cleanup switch
2018-01-14 01:20:13 -05:00
Ethan Buchman
3368eeb03e fix tests 2018-01-14 01:19:07 -05:00
Ethan Buchman
68237911ba NetAddress.Same checks ID or DialString 2018-01-14 01:15:37 -05:00
Ethan Buchman
f9e4f6eb6b reorder peer.go methods 2018-01-14 01:15:37 -05:00
Ethan Buchman
8b74a8d6ac NodeInfo not a pointer 2018-01-14 01:15:33 -05:00
Ethan Buchman
08f84cd712 a little more moving around 2018-01-13 23:56:57 -05:00
Ethan Buchman
452d10f368 cleanup switch 2018-01-13 17:37:52 -05:00
Ethan Buchman
8b3fb743cf Merge pull request #1048 from tendermint/p2p-id
P2P ID
2018-01-13 17:35:21 -05:00
Ethan Buchman
7667e11973 remove RemoteAddr from NodeInfo 2018-01-13 17:36:03 -05:00
Ethan Buchman
53a5498fc5 more fixes from review 2018-01-13 17:34:12 -05:00
Ethan Buchman
e4d52401cf some fixes from review 2018-01-13 16:06:51 -05:00
Ethan Buchman
9670519a21 remove PoW from ID 2018-01-13 15:50:59 -05:00
Ethan Buchman
b1485b181a Merge branch 'p2p-consolidate' into p2p-id 2018-01-13 15:20:23 -05:00
Ethan Buchman
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
Ethan Buchman
c1e167e330 note in trust metric test 2018-01-13 15:11:13 -05:00
Ethan Buchman
e2b3b5b58c dial_persistent_peers -> dial_peers with persistent option 2018-01-13 14:50:58 -05:00
Ethan Buchman
e6b70baae0 Merge branch 'develop' into 864-distinguish-between-seeds-and-manual-peers 2018-01-13 14:34:32 -05:00
Anton Kaliaev
b40aa91b41 document event subscriptions
Refs #1100
2018-01-12 12:53:34 -06:00
Ethan Buchman
a13b17ec6c Merge pull request #792 from tendermint/config
Config Improvements
2018-01-10 14:41:30 -05:00
Ethan Buchman
b32a507a1b Merge pull request #1088 from tendermint/1087-update-docker
Update docker image
2018-01-10 14:23:06 -05:00
Ethan Buchman
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
Anton Kaliaev
c79ba3c349 document the maximum supported voting power due to overflow [ci skip]
Refs #1075
2018-01-10 14:21:26 -05:00
Anton Kaliaev
12ca972761 Merge branch 'develop' into 1087-update-docker 2018-01-10 11:08:14 -06:00
Zach Ramsay
657ad214cb p2p tests: put priv_val in right place 2018-01-10 16:30:00 +00:00
Zach
39acf1c5e8 Merge branch 'develop' into config 2018-01-10 14:21:24 +00:00
Anton Kaliaev
075ae1e301 minimal test for dialing seeds in pex reactor 2018-01-09 18:29:29 -06:00
Anton Kaliaev
705d51aa42 move dialSeedsIfAddrBookIsEmptyOrPEXFailedToConnect into PEX reactor 2018-01-09 17:54:29 -06:00
Anton Kaliaev
ef0493ddf3 rewrite Peers section of Using Tendermint guide [ci skip] 2018-01-09 17:54:28 -06:00
Anton Kaliaev
1b455883d2 readd /dial_seeds 2018-01-09 17:54:28 -06:00
Anton Kaliaev
e4897b7bdd rename manual peers to persistent peers 2018-01-09 16:18:05 -06:00
Anton Kaliaev
37f86f9518 update changelog [ci skip] 2018-01-09 16:04:07 -06:00
Anton Kaliaev
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
Anton Kaliaev
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
Zach
c521f385a6 add quick start guide (#1069) 2018-01-09 20:35:47 +00:00
Anton Kaliaev
b8214fce66 Merge branch 'develop' into 1087-update-docker 2018-01-09 12:21:23 -06:00
Ethan Buchman
03a14d8342 docs/p2p: updates from review (#1076) 2018-01-09 11:44:49 -06:00
Anton Kaliaev
48638eaa20 update docker readme 2018-01-09 11:05:15 -06:00
Anton Kaliaev
170777300e update docker
Closes #1087
2018-01-09 11:04:37 -06:00
Adrian Brink
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
Ethan Buchman
b9cbaf8f10 priv-val: fix timestamp for signing things that only differ by timestamp 2018-01-08 16:36:16 -05:00
Ethan Buchman
8d86b6c2d2 Merge pull request #1084 from tendermint/fix-make-dist-script
fix broken `make dist` target
2018-01-08 16:20:36 -05:00
Anton Kaliaev
555f560ecd fix broken make dist target 2018-01-08 13:13:47 -06:00
Zarko Milosevic
dba4815616 Define requirements of the proposer selection procedure 2018-01-08 14:10:01 +01:00
Ethan Buchman
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
Ethan Buchman
90c691df2b Merge pull request #1063 from tendermint/feature/Issue1020
NewInquiring returns error instead of swallowing it
2018-01-07 16:30:33 -05:00
Adrian Brink
13fa23c568 Add error checking 2018-01-06 22:24:58 +01:00
Jae Kwon
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
Jae Kwon
a034600024 Revert "Changes to achieve a standardized build process and deterministic builds" 2018-01-05 22:35:57 -08:00
Zach
e0e600df05 Merge branch 'develop' into config 2018-01-06 05:30:38 +00:00
Ethan Buchman
92f5ae5a84 fix vagrant [ci skip] 2018-01-05 22:26:10 -05:00
Ethan Buchman
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
Greg Szabo
bb3dc10f24 Makefile improvements for deterministic builds based on Bucky's feedback 2018-01-05 14:22:13 -05:00
Greg Szabo
2cc50938a4 Merge branch 'develop' into feature/buildprocess 2018-01-05 13:01:40 -05:00
Adrian Brink
ba475d3128 Fix formatting 2018-01-05 13:25:58 +01:00
Adrian Brink
ed81fb54ec NewInquiring returns error instead of swallowing it 2018-01-05 13:24:16 +01:00
Ethan Buchman
8481da2405 Merge pull request #1046 from tendermint/abci-spec-docs
docs: add abci spec
2018-01-04 13:57:40 -05:00
Ethan Buchman
ecb7303e35 Merge branch 'develop' into abci-spec-docs 2018-01-04 13:57:08 -05:00
Ethan Frey
9cb45eb7df Add skeleton for functionality and concurrency 2018-01-04 19:08:03 +01:00
Ethan Buchman
6855e62f0a Merge pull request #1052 from tendermint/feature/p2p_docs
docs: P2P Documentation
2018-01-04 12:32:28 -05:00
Ethan Frey
17b61db40a Document p2p and rpc messages 2018-01-04 18:12:48 +01:00
Ethan Frey
7b52499463 Start writing mempool specification
Include overview and configuration options.
2018-01-04 17:11:35 +01:00
Greg Szabo
f67f99c227 Extended install document with docker option. Added extra checks to developer's build target. 2018-01-03 17:24:11 -05:00
Greg Szabo
0430ebf95c Makefile changes for cross-building and standardized builds using gox 2018-01-03 14:58:23 -05:00
Adrian Brink
f602de437e Move P2P docs into docs folder 2018-01-03 10:49:47 +01:00
Zach Ramsay
a573b20888 docs: add counter/dummy code snippets
closes https://github.com/tendermint/abci/issues/134
2018-01-03 01:23:38 +00:00
Ethan Buchman
488ae529ad p2p: authenticate peer ID 2018-01-01 23:23:11 -05:00
Ethan Buchman
6e823c6e87 p2p: support addr format ID@IP:PORT 2018-01-01 23:08:20 -05:00
Ethan Buchman
7d35500e6b p2p: add ID to NetAddress and use for AddrBook 2018-01-01 22:39:08 -05:00
Ethan Buchman
a17105fd46 p2p: peer.Key -> peer.ID 2018-01-01 22:39:05 -05:00
Ethan Buchman
b289d2baf4 persistent node key and ID 2018-01-01 21:21:42 -05:00
Ethan Buchman
f2e0abf1dc p2p: reorder some checks in addPeer; add comments to NodeInfo 2018-01-01 21:21:39 -05:00
Ethan Buchman
528154f1a2 p2p: PrivKey need not be Ed25519 2018-01-01 19:44:01 -05:00
Ethan Buchman
bc71840f06 more p2p docs 2018-01-01 16:30:36 -05:00
Zach Ramsay
cd15b677ec docs: add abci spec 2018-01-01 15:35:28 +00:00
Ethan Buchman
1acb12edf5 p2p docs 2017-12-31 17:11:09 -05:00
Ethan Buchman
008de93bbe Merge pull request #1039 from tendermint/add_consensus_spec
Spec of consensus/gossip protocol
2017-12-31 14:59:32 -05:00
Zach
4e834baa9a docs: update ecosystem.rst (#1037)
* docs: update ecosystem.rst

* typo [ci skip]
2017-12-31 13:54:50 +00:00
Zarko Milosevic
96e0e4ab5a Describe messages sent as part of consensus/gossip protocol 2017-12-30 21:18:12 +01:00
Ethan Buchman
381fe19335 changelog date [ci skip] 2017-12-29 17:51:19 -05:00
Ethan Buchman
ff99ca7cdf bump wal test timeout 2017-12-29 17:51:13 -05:00
Ethan Buchman
60f95cd9ea changelog and version 2017-12-29 11:28:44 -05:00
Ethan Buchman
28bbeac763 state: send byzantine validators in BeginBlock 2017-12-29 11:26:55 -05:00
Ethan Buchman
e97e0bacd1 update glide 2017-12-29 11:11:13 -05:00
Ethan Buchman
abfdfe67e8 test/p2p: add some timeouts 2017-12-29 11:02:47 -05:00
Ethan Buchman
992371b4cf Merge pull request #1035 from tendermint/readme-min-requirements
README: document the minimum Go version
2017-12-29 10:24:57 -05:00
Ethan Buchman
07eeddc5e1 Merge pull request #1015 from tendermint/state_funcs
state: move methods to funcs
2017-12-29 10:24:22 -05:00
Emmanuel Odeke
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
Ethan Buchman
444db4c242 metalinter 2017-12-28 23:15:54 -05:00
Ethan Buchman
cb845ebff5 fix EvidencePool and VerifyEvidence 2017-12-28 23:15:54 -05:00
Ethan Buchman
6112578d07 ValidateBlock is a method on blockExec 2017-12-28 23:15:54 -05:00
Ethan Buchman
ae68fcb78a move fireEvents to ApplyBlock 2017-12-28 23:15:54 -05:00
Ethan Buchman
8d8d63c94c changelog 2017-12-28 23:15:54 -05:00
Ethan Buchman
1d6f00859d fixes from review 2017-12-28 23:15:54 -05:00
Ethan Buchman
397251b0f4 fix evidence 2017-12-28 23:15:54 -05:00
Ethan Buchman
537b0dfa1a use NopEventBus 2017-12-28 23:15:54 -05:00
Ethan Buchman
0acca7fe69 final updates for state 2017-12-28 23:15:54 -05:00
Ethan Buchman
bac60f2067 blockchain: update for new state 2017-12-28 23:15:54 -05:00
Ethan Buchman
f82b7e2a13 state: re-order funcs. fix tests 2017-12-28 23:15:54 -05:00
Ethan Buchman
9e6d088757 state: BlockExecutor 2017-12-28 23:15:54 -05:00
Ethan Buchman
c915719f85 *State->State; SetBlockAndValidators->NextState 2017-12-28 23:15:54 -05:00
Ethan Buchman
f55135578c state: move methods to funcs 2017-12-28 23:15:54 -05:00
Ethan Buchman
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
Ethan Buchman
a8e625e99d config: unexpose chainID 2017-12-28 20:49:02 +00:00
Zach Ramsay
a92a32b862 config: lil fixes 2017-12-28 20:49:02 +00:00
Zach Ramsay
9da5cd0180 rebase fix 2017-12-28 20:49:02 +00:00
Anton Kaliaev
a6f2e502e7 move genesis.json file into config dir 2017-12-28 20:49:02 +00:00
Anton Kaliaev
69d8c2e554 fixes after my own review 2017-12-28 20:49:02 +00:00
Zach Ramsay
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
Anton Kaliaev
75182f7205 change directory for each call, not only for each test
Fixes #1026
2017-12-28 11:17:15 -06:00
Ethan Buchman
41caa4415c Merge pull request #1024 from tendermint/1023-tendermint-version
remove quotes from `tendermint version`
2017-12-28 10:14:39 -05:00
Anton Kaliaev
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
Ethan Buchman
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
Anton Kaliaev
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
Ethan Buchman
1a0db878bf Merge pull request #1009 from tendermint/spec
Spec
2017-12-27 15:23:13 -05:00
Ethan Buchman
53eb9aca2b Merge pull request #592 from tendermint/evidence
track evidence, include in block
2017-12-27 15:22:24 -05:00
Ethan Buchman
caccabd4e5 spec: fixes from review 2017-12-27 15:14:49 -05:00
Ethan Buchman
d0e0ac5fac types: better error messages for votes 2017-12-27 14:46:24 -05:00
Ethan Buchman
7d81a3f4a5 address some comments from review 2017-12-27 01:27:03 -05:00
Ethan Buchman
f95b7529eb Merge pull request #999 from tendermint/feature/result-hash-header
Add results hash to header
2017-12-26 20:49:20 -05:00
Ethan Buchman
6a4fd46479 fixes from rebase 2017-12-26 20:42:34 -05:00
Ethan Buchman
b01b1e4758 remove unused var 2017-12-26 20:27:40 -05:00
Ethan Buchman
014b0b9944 evidence: reactor test 2017-12-26 20:27:40 -05:00
Ethan Buchman
5904f6df8b minor fixes from review 2017-12-26 20:27:40 -05:00
Ethan Buchman
0f293bfc2b remove some TODOs 2017-12-26 20:27:40 -05:00
Ethan Buchman
cfbedec719 evidence: reactor test 2017-12-26 20:27:40 -05:00
Ethan Buchman
666ae244b3 evidence: pool test 2017-12-26 20:27:40 -05:00
Ethan Buchman
c13e93d63e evidence: store tests and fixes 2017-12-26 20:27:40 -05:00
Ethan Buchman
c2585b5525 evidence_pool.go -> pool.go. remove old test files 2017-12-26 20:27:40 -05:00
Ethan Buchman
1d021c2790 update consensus/test_data/many_blocks.cswal 2017-12-26 20:27:40 -05:00
Ethan Buchman
cc418e5dab state.VerifyEvidence enforces EvidenceParams.MaxAge 2017-12-26 20:27:32 -05:00
Ethan Buchman
c7acdfadf2 evidence: more funcs in store.go 2017-12-26 20:27:32 -05:00
Ethan Buchman
869d873d5c state.ApplyBlock takes evpool and calls MarkEvidenceAsCommitted 2017-12-26 20:27:32 -05:00
Ethan Buchman
3271634e7a types: evidence cleanup 2017-12-26 20:26:21 -05:00
Ethan Buchman
4854c231e1 evidence store comments and cleanup 2017-12-26 20:26:21 -05:00
Ethan Buchman
7a18fa887d evidence linked with consensus/node. compiles 2017-12-26 20:26:21 -05:00
Ethan Buchman
6c4a0f9363 cleanup evidence pkg. state.VerifyEvidence 2017-12-26 20:26:21 -05:00
Ethan Buchman
f7731d38f6 some comments and cleanup 2017-12-26 20:25:14 -05:00
Ethan Buchman
df3f4de7c3 check evidence is from validator; some cleanup 2017-12-26 20:25:14 -05:00
Ethan Buchman
10c43c9edc introduce evidence store 2017-12-26 20:25:14 -05:00
Ethan Buchman
fe4b53a463 EvidencePool 2017-12-26 20:24:54 -05:00
Ethan Buchman
5b1f987ed1 mempool: remove Peer interface. use p2p.Peer 2017-12-26 20:24:12 -05:00
Ethan Buchman
48d778c4b3 types/params: introduce EvidenceParams 2017-12-26 20:24:12 -05:00
Ethan Buchman
7d086e9524 check if we already have evidence 2017-12-26 20:21:17 -05:00
Ethan Buchman
6e9433c7a8 post rebase fix 2017-12-26 20:21:17 -05:00
Ethan Buchman
39299e5cc1 consensus: note about duplicate evidence 2017-12-26 20:21:17 -05:00
Ethan Buchman
eeab0efa56 types: tx.go comments 2017-12-26 20:21:17 -05:00
Ethan Buchman
77e45756f2 types: Evidences for merkle hashing; Evidence.String() 2017-12-26 20:21:17 -05:00
Ethan Buchman
9cdcffbe4b types: comments; compiles; evidence test 2017-12-26 20:21:17 -05:00
Ethan Buchman
50850cf8a2 verify sigs on both votes; note about indices 2017-12-26 20:21:17 -05:00
Ethan Buchman
35587658cd verify evidence in block 2017-12-26 20:21:17 -05:00
Ethan Buchman
4661c98c17 add pubkey to conflicting vote evidence 2017-12-26 20:21:17 -05:00
Ethan Buchman
7928659f70 track evidence, include in block 2017-12-26 20:21:17 -05:00
Ethan Buchman
f80f6445a6 fix test 2017-12-26 20:15:09 -05:00
Ethan Buchman
336c2f4fe1 rpc: fix getHeight 2017-12-26 20:08:25 -05:00
Ethan Buchman
bfcb40bf6b validate block.ValidatorsHash 2017-12-26 20:00:45 -05:00
Ethan Buchman
051c2701ab remove LastConsensusParams 2017-12-26 19:56:39 -05:00
Ethan Buchman
028ee58580 call it LastResultsHash 2017-12-26 19:53:26 -05:00
Ethan Buchman
801e3dfacf rpc: getHeight helper function 2017-12-26 19:37:42 -05:00
Ethan Buchman
4171bd3bae fixes 2017-12-26 19:24:45 -05:00
Ethan Buchman
73fb1c3a17 consolidate saveResults/SaveABCIResponses 2017-12-26 19:24:45 -05:00
Ethan Frey
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
Ethan Frey
58c5df729b Add ResultHash to header 2017-12-26 19:24:25 -05:00
Ethan Frey
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
Ethan Frey
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
Ethan Buchman
d844799b3b Merge branch '950-enforce-less-13-val-changes-per-block' into develop 2017-12-26 19:22:21 -05:00
Ethan Buchman
3ea1145486 bring back test 2017-12-26 19:22:15 -05:00
Ethan Buchman
d4716fc03c state 2017-12-26 18:43:03 -05:00
Ethan Buchman
16227594ef notes about block 1 2017-12-26 16:33:42 -05:00
Ethan Buchman
65cdb07f0c merkle 2017-12-26 15:48:17 -05:00
Ethan Buchman
eb73e82279 encoding.md 2017-12-26 15:30:56 -05:00
Ethan Buchman
d6fbfddddd spec.md -> blockchain.md. some fixes 2017-12-26 15:30:27 -05:00
Anton Kaliaev
1339a44402 add safe*Clip funcs 2017-12-26 14:13:12 -06:00
Anton Kaliaev
b8215d8ac8 more test cases 2017-12-26 13:30:00 -06:00
Ethan Buchman
289d92c97d consensus: remove log stmt. closes #987 2017-12-26 10:41:31 -05:00
Ethan Buchman
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
Anton Kaliaev
69c3a7640b add safeAdd & safeSub plus quickcheck tests 2017-12-25 18:39:14 -06:00
Anton Kaliaev
e8b0458f16 check for overflow and underflow while choosing proposer
Refs #919
2017-12-25 18:39:14 -06:00
Anton Kaliaev
6b89639f90 update docs 2 [ci skip] 2017-12-25 17:58:15 -06:00
Anton Kaliaev
9b25f7325a update docs [ci skip] 2017-12-25 17:53:54 -06:00
Anton Kaliaev
0093f9877a change voting power change, not number of vals 2017-12-25 17:49:36 -06:00
Anton Kaliaev
cf0b5d3715 enforce <1/3 validator updates
Refs #950
2017-12-25 12:10:53 -06:00
Ethan Buchman
616f7e74db Merge pull request #1001 from tendermint/makefile
Cleaned up makefile
2017-12-25 12:09:10 -05:00
Ethan Buchman
14c812a39c tmlibs timer fix 2017-12-25 11:11:55 -05:00
Ethan Buchman
1e52751344 update tests for makefile 2017-12-25 10:24:41 -05:00
Jae Kwon
d7ac6e516a Cleaned up makefile 2017-12-23 02:23:05 -08:00
Ethan Buchman
c2436c46e6 Merge pull request #972 from tendermint/feature/enhance-endblock
Update EndBlock parameters
2017-12-22 01:30:58 -05:00
Ethan Buchman
e3585a6eb0 wip: tendermint specification 2017-12-21 22:36:37 -05:00
Ethan Buchman
38608b1b0f comment and tmlibs fix 2017-12-21 18:32:40 -05:00
Ethan Buchman
2b634dab32 Merge pull request #994 from tendermint/clean/block-validation
Clean/block validation
2017-12-21 17:53:11 -05:00
Ethan Buchman
91acc51cd1 fix test 2017-12-21 17:52:06 -05:00
Ethan Buchman
dc54ba67e4 state: TestValidateBlock 2017-12-21 17:51:03 -05:00
Ethan Buchman
35521b553a save historical consensus params 2017-12-21 17:46:25 -05:00
Ethan Buchman
70a744558c types: params.Update() 2017-12-21 17:00:52 -05:00
Ethan Buchman
4b789ff7e9 another cmn fix 2017-12-21 16:49:47 -05:00
Ethan Buchman
306657a118 no patience for metalinter right now 2017-12-21 16:49:47 -05:00
Ethan Buchman
be765e4cb9 update glide for cmn fixes 2017-12-21 16:49:47 -05:00
Ethan Buchman
b5857da877 forgot file 2017-12-21 16:49:47 -05:00
Ethan Buchman
3ad055ef3a fix randPort 2017-12-21 16:49:47 -05:00
Ethan Buchman
3d00c477fc separate block vs state based validation 2017-12-21 16:49:47 -05:00
Ethan Buchman
c2912d612a update glide 2017-12-21 16:49:47 -05:00
Ethan Buchman
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
Ethan Buchman
f81025631e update comment [ci skip] 2017-12-21 16:28:05 -05:00
Ethan Buchman
9c03c58de2 priv validator checks if only difference is timestamp; else error 2017-12-21 15:37:27 -05:00
Anton Kaliaev
0ffd60b8cf ValidatorSetUpdates -> ValidatorUpdates 2017-12-21 11:52:26 -06:00
Ricardo Domingos
d5baa6601c types: Add test for IsVoteTypeValid 2017-12-21 18:13:31 +01:00
Ricardo Domingos
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
Ricardo Domingos
e76392e330 types: Update String() test to assert Prevote type 2017-12-20 23:21:30 +01:00
Anton Kaliaev
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
Emmanuel T Odeke
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
Anton Kaliaev
843e1ed400 Updates -> ValidatoSetUpdates 2017-12-19 13:03:39 -06:00
Ethan Buchman
4bca6bf6f5 fix test 2017-12-19 12:30:34 -05:00
Ethan Frey
960b25408f Store LastConsensusHash in State as well
Update all BlockValidation that it matches the last state
2017-12-19 12:28:08 -05:00
Ethan Frey
45bc106de7 Updated lite tests to set ConsensusHash in header 2017-12-19 12:28:08 -05:00
Ethan Frey
d151e36ea8 Add ConsensusHash to header 2017-12-19 12:28:08 -05:00
Ethan Frey
56cada6a0c Validate ConsensusParams returned from abci app 2017-12-19 12:28:08 -05:00
Ethan Frey
a0b2d77bef Add hash to ConsensusParams 2017-12-19 12:28:08 -05:00
Ethan Frey
030fd00232 Added tests for applying consensus param changes 2017-12-19 12:28:08 -05:00
Ethan Frey
d21f39160f Apply ConsensusParamChanges to state/State 2017-12-19 12:28:08 -05:00
Ethan Frey
4265a94bfe Update EndBlock parameters
* Update abci dependencies
* Modify references from Diffs to Changes
* Fixes issues #924
2017-12-19 12:28:08 -05:00
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
e0fe84a856 Merge branch 'develop' into 977-wal-generator 2017-12-19 11:11:26 -05:00
Ethan Buchman
783ffdb7fd Merge pull request #983 from tendermint/circle-testing
Circle testing
2017-12-19 11:09:22 -05:00
Ethan Buchman
cb3ac6987e remove some debugs 2017-12-19 10:11:37 -05:00
Anton Kaliaev
5a83e58428 stop eventBus 2017-12-17 20:16:02 -06:00
Anton Kaliaev
3f02ab0ead unidirectional channel 2017-12-16 22:20:07 -06:00
Anton Kaliaev
99c58fc561 enable logging for wal_generator and set timeout to 1 min
Refs #977
2017-12-16 21:59:10 -06:00
Ethan Buchman
a86df17ceb crank city 2017-12-16 19:55:04 -05:00
Ethan Buchman
5d04ccbe51 excessive logging. update tmlibs for timer fix 2017-12-16 19:16:08 -05:00
Ethan Buchman
61dc357bb3 test/p2p/kill_all: longer timeout 2017-12-16 13:36:52 -05:00
Ethan Buchman
d7cb2f850d more logs in p2p 2017-12-16 13:36:52 -05:00
Ethan Buchman
bfe0a4a8ac more logging 2017-12-16 13:36:52 -05:00
Ethan Buchman
0ec7909ec3 more logging in p2p and consensus 2017-12-16 13:36:52 -05:00
Ethan Buchman
b5b912e2c4 Merge remote-tracking branch 'origin/977-wal-generator' into develop 2017-12-16 13:36:32 -05:00
Ethan Buchman
9504a593e9 Merge pull request #980 from tendermint/fix-test-in-develop
add missing Timestamp to Votes
2017-12-15 22:11:47 -05:00
Anton Kaliaev
f8f28c8942 enable logging for wal_generator and set timeout to 1 min
Refs #977
2017-12-15 16:15:09 -06:00
Anton Kaliaev
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
Anton Kaliaev
c513649df4 strip protocol if defined
Fixes #934
2017-12-15 13:36:08 -06:00
Anton Kaliaev
a6911825b0 PanicCrisis is deprecated 2017-12-15 13:35:49 -06:00
Ethan Buchman
eddabab5e4 Merge pull request #965 from tendermint/573-handle-corrupt-wal-file
Handle corrupt WAL file
2017-12-15 14:33:16 -05:00
Ethan Buchman
3eee69de2d Merge pull request #954 from tendermint/668-send-absent-validators
Send absent validators
2017-12-15 13:55:52 -05:00
Ethan Buchman
068d83bce8 Merge pull request #677 from tendermint/blockchain-test-store
blockchain: add tests for BlockStore
2017-12-15 13:33:55 -05:00
Anton Kaliaev
7f649ccf23 fixes from Frey's review 2017-12-15 12:21:15 -06:00
Anton Kaliaev
808b830942 add a unit test
Refs #668
2017-12-15 12:13:02 -06:00
Anton Kaliaev
d669816a1b send absent validators in BeginBlock
Refs #668
2017-12-15 12:13:02 -06:00
Anton Kaliaev
e40689b9cc PanicCrisis is deprecated 2017-12-15 11:59:45 -06:00
Anton Kaliaev
709cf18aef add gofuzz test for consensus wal 2017-12-15 11:56:24 -06:00
Anton Kaliaev
e57cad6c3f correct maxMsgSizeBytes 2017-12-15 11:42:53 -06:00
Anton Kaliaev
4f94caa1b9 explain what to do in case of truncation [ci skip] 2017-12-15 11:11:21 -06:00
Ethan Buchman
78a682e4b6 blockchain: test fixes 2017-12-15 12:07:48 -05:00
Ethan Buchman
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
Anton Kaliaev
72da553ed9 add missing Timestamp to Vote
Fixes #974
2017-12-13 22:24:06 -06:00
Anton Kaliaev
b78606d94f Merge pull request #967 from tendermint/feature/total-tx
Add TotalTx to block header
2017-12-13 17:09:48 -06:00
Ethan Frey
a6f719a402 Add tests for block validation 2017-12-13 19:54:16 +01:00
Anton Kaliaev
e0fbd148ef Merge pull request #958 from tendermint/pex-on-by-default
activate PEX reactor by default
2017-12-13 12:52:17 -06:00
Anton Kaliaev
2f91289880 update changelog [ci skip] 2017-12-13 12:26:12 -06:00
Ethan Buchman
462b755a60 activate PEX reactor by default 2017-12-13 12:25:48 -06:00
Anton Kaliaev
0a2ecaa393 Merge pull request #953 from tendermint/feature/time-fields
Add Timestamp to Proposal/Vote
2017-12-13 12:18:55 -06:00
Ethan Frey
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
Ethan Buchman
64f056b57d Merge branch '916-remove-sleeps-from-tests' into develop 2017-12-12 16:43:36 -05:00
Ethan Buchman
90df9fa1bf p2p/trust: remove extra channels 2017-12-12 16:43:19 -05:00
caffix
eae6e6381e trust metric is now a service and the test ticker has been added 2017-12-12 15:33:42 -05:00
Anton Kaliaev
04a18e0a97 briefly describe the recover process [ci skip] 2017-12-12 13:03:09 -06:00
Anton Kaliaev
06aece31cf lower the max message size 2017-12-12 13:02:40 -06:00
Ethan Buchman
e0296d6c3c consensus: fix makeBlockchainFromWAL 2017-12-12 12:14:15 -05:00
Ethan Frey
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
Ethan Frey
8576ad58bd Cleanup canonical json 2017-12-12 12:59:51 +01:00
Ethan Frey
c4860f6c29 Force CanonicalTime to UTC
fixes issue with vote serialization breaking the signatures
2017-12-12 12:59:51 +01:00
Ethan Frey
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
Ethan Frey
a29c781295 Add default timestamp to all instances of *types.Vote 2017-12-12 12:59:51 +01:00
Ethan Frey
599673690c Add timestamp to vote canonical encoding 2017-12-12 12:59:51 +01:00
Ethan Frey
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
Ethan Buchman
5ecae52bf1 Merge branch 'master' into develop 2017-12-12 02:31:47 -05:00
Ethan Buchman
ac2d0edb2f Merge pull request #964 from tendermint/fix-gometa-makefile
fix gometalinter.v2 automatically
2017-12-12 02:26:18 -05:00
Petabyte Storage
ae632654d2 add tools check with short circuit 2017-12-11 23:00:18 -08:00
Ethan Buchman
88f5f21dbb Merge pull request #960 from tendermint/release-v0.14.0
Release v0.14.0
2017-12-12 01:28:35 -05:00
Petabyte Storage
49e5510953 remove tools from all 2017-12-11 21:44:53 -08:00
Anton Kaliaev
a6644f7477 remove gopath prefixes
it's safe because I added GOPATH to PATH earlier today
2017-12-11 23:05:22 -06:00
Anton Kaliaev
10265d8667 add tools to make all because it's required for test target 2017-12-11 23:02:42 -06:00
Petabyte Storage
8be708fe5b fix spelling and makefile gometalinter.v2 2017-12-11 20:48:15 -08:00
Ethan Buchman
5facfafbd5 Merge branch 'develop' into release-v0.14.0 2017-12-11 23:09:04 -05:00
Ethan Buchman
11761d1769 initial port of cosmos-sdk basecli proxy 2017-12-11 22:23:13 -05:00
Ethan Buchman
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
Ethan Buchman
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
Anton Kaliaev
af79a2a59e fix error msg 2017-12-11 19:50:05 -06:00
Anton Kaliaev
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
Anton Kaliaev
40f9261d48 handle data corruption errors
Refs #573
2017-12-11 19:48:20 -06:00
Anton Kaliaev
69205594cc add gopath to path on CircleCI 2017-12-11 16:59:08 -06:00
Anton Kaliaev
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
Anton Kaliaev
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
Ethan Buchman
2af32d6665 changelog and version bump 2017-12-11 15:05:56 -05:00
Ethan Buchman
5c58db3bb4 changelog [ci skip] 2017-12-11 14:49:34 -05:00
Ethan Buchman
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
Ethan Buchman
5511bd8e85 p2p: exponential backoff on reconnect. closes #939 2017-12-11 13:41:09 -05:00
Ethan Buchman
f1ca2b3a3a Merge pull request #698 from tendermint/feat-appveyor
WIP: Run tests on AppVeyor
2017-12-10 20:06:34 -05:00
Ethan Buchman
10fcefe346 appveyor: use make 2017-12-10 20:07:44 -05:00
Ethan Buchman
0bfc11f1ba blockchain: note about store tests needing simplification ... 2017-12-10 20:03:58 -05:00
Emmanuel Odeke
96998a5498 blockchain: Block creator helper for compressing tests as per @ebuchman 2017-12-10 19:58:22 -05:00
Emmanuel Odeke
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
Emmanuel Odeke
83b40b25d6 blockchain: deduplicate store header value tests 2017-12-10 19:57:06 -05:00
Emmanuel Odeke
05f30b3e28 blockchain: updated store docs/comments from review 2017-12-10 19:57:06 -05:00
Ethan Buchman
116a61beb1 blockchain: update store comments 2017-12-10 19:57:06 -05:00
Emmanuel Odeke
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
Ethan Buchman
41bb2c2663 Merge pull request #931 from tendermint/785-wal-improvements
[consensus] remove WAL separator
2017-12-10 19:46:02 -05:00
Ethan Buchman
e7b9cd8ee8 Merge branch 'develop' into 785-wal-improvements 2017-12-10 19:45:52 -05:00
Ethan Buchman
3019b9f320 Merge pull request #948 from tendermint/945-transparent-websocket
bring back transparent websocket (Refs #945)
2017-12-10 19:05:32 -05:00
Ethan Buchman
60872d7d7c Merge pull request #949 from tendermint/docs/trust-metric-usage
Docs/trust metric usage
2017-12-10 19:01:16 -05:00
Ethan Buchman
a37c1143ca adr: update 007 trust metric usage 2017-12-10 19:00:44 -05:00
caffix
4e08ee1833 made clarifications based on odeke-em's PR comments 2017-12-10 15:39:43 -05:00
caffix
7563870d11 added the trust metric usage guide 2017-12-10 15:39:43 -05:00
Zach
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
Anton Kaliaev
101680d603 update changelog [ci skip] 2017-12-10 11:35:22 -06:00
Anton Kaliaev
d819d5d324 update changelog [ci skip] 2017-12-10 11:34:08 -06:00
Anton Kaliaev
90cdffa067 fixes after my own review (Refs #945) 2017-12-10 11:29:36 -06:00
Ethan Buchman
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
Anton Kaliaev
950a64f756 bring back transparent websocket (Refs #945) 2017-12-10 01:18:10 -06:00
Anton Kaliaev
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
Anton Kaliaev
4f50935aa2 Merge pull request #946 from ricardohsd/fix-typo
consensus: Fix typo on ticker.go documentation
2017-12-09 17:03:12 -06:00
caffix
44f62e5e27 built the WaitForStop functionality into the Stop method 2017-12-09 13:25:28 -05:00
Ricardo Domingos
59e89e7664 consensus: Fix typo on ticker.go documentation 2017-12-09 13:14:53 +01:00
caffix
5d464364a8 fixed the racy test and removed all the calls to Sleep 2017-12-08 15:51:18 -05:00
Ethan Frey
2112299586 Cleanup apt-get ala PR comments 2017-12-08 19:20:53 +01:00
Ethan Frey
c771964a40 Add vagrant_test to Makefile for integration tests 2017-12-08 18:36:58 +01:00
Anton Kaliaev
a199ec2813 update docker readme 2017-12-08 11:35:35 -06:00
Anton Kaliaev
a28b3fff49 update Dockerfile to 0.13.0 2017-12-08 11:34:34 -06:00
Ethan Frey
5bcd95f01f Use apt-get/ppa instead of tarballs for golang/docker
Minor cleanup and comments
2017-12-08 18:10:39 +01:00
Ethan Frey
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
Anton Kaliaev
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
Ethan Buchman
fbfd11de2c add @melekes as codeowner 2017-12-08 11:48:05 -05:00
Ethan Frey
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
Ethan Buchman
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
Ethan Buchman
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
Anton Kaliaev
7a92a3b729 update docker readme 2017-12-07 13:49:29 -06:00
Anton Kaliaev
457c688346 update Dockerfile to point to 0.12.1 2017-12-07 13:48:31 -06:00
Anton Kaliaev
c609b18698 tolerate unresolvable seeds (Refs #880) 2017-12-07 13:17:09 -06:00
Anton Kaliaev
5ff0bb2100 default moniker to the host name (Refs #920) 2017-12-07 12:49:29 -06:00
Anton Kaliaev
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
Anton Kaliaev
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
Ethan Buchman
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
Anton Kaliaev
5cb936fa00 fixes after my own review 2017-12-06 18:28:14 -06:00
Anton Kaliaev
c6f025f40e generate WAL on the fly (Refs #468) 2017-12-06 16:01:08 -06:00
Ethan Buchman
a2b92c0745 Merge pull request #927 from tendermint/release-v0.13.0
Release v0.13.0
2017-12-06 03:57:49 -05:00
Ethan Buchman
6884463ba2 update changelog [ci skip] 2017-12-06 03:38:03 -05:00
Ethan Buchman
167d0e82f9 fixes and version bump 2017-12-06 03:33:03 -05:00
Ethan Buchman
42e77de6a3 changelog; minor stuff; update glide 2017-12-06 02:45:38 -05:00
Ethan Buchman
58b4a8395b Merge pull request #917 from tendermint/trust-metric-cleanup
Trust metric cleanup
2017-12-06 02:11:38 -05:00
Ethan Buchman
d0dc04001e rpc: make time human readable. closes #926 2017-12-06 01:25:11 -05:00
Ethan Buchman
e101aa9fc8 fix for legacy gowire 2017-12-06 01:21:14 -05:00
Ethan Buchman
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
Anton Kaliaev
b3e1341e44 use get rev-parse --short HEAD everywhere instead of GitCommit[:8] 2017-12-04 22:16:19 -06:00
Anton Kaliaev
ebdc7ddf20 add missing get_vendor_deps to "make all" 2017-12-04 19:04:15 -06:00
Anton Kaliaev
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
Anton Kaliaev
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
Anton Kaliaev
440d76647d rename release to test_release 2017-12-04 17:37:32 -06:00
Anton Kaliaev
2cc2fade06 remove -extldflags "-static"
golang builds static libraries by default.
2017-12-04 17:35:42 -06:00
Anton Kaliaev
e50173c7dc merge 2 rules in .editorconfig 2017-12-04 15:01:28 -06:00
Anton Kaliaev
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
Ethan Buchman
b37230f6db Merge pull request #918 from tendermint/abci-update
Abci update
2017-12-03 01:36:59 -05:00
Ethan Buchman
1bf57a90df glide: update grpc version 2017-12-02 23:41:12 -05:00
Ethan Buchman
d2db202a2d mempool: assert -> require in test 2017-12-02 23:41:09 -05:00
Ethan Buchman
08857606dc test: fix test/app/counter_test.sh 2017-12-02 23:39:19 -05:00
Ethan Buchman
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
Anton Kaliaev
d41c0b10c8 change delta's type from int to int64 2017-12-02 11:48:24 -06:00
Ethan Buchman
898ae53672 types: fix for broken customtype int in gogo 2017-12-02 12:00:46 -05:00
Ethan Buchman
9e20cfee0e glide 2017-12-02 01:56:40 -05:00
Ethan Buchman
9af8da7aad update for new abci int types 2017-12-02 01:47:55 -05:00
Ethan Buchman
c9be2b89f9 mempool: return error on cached txs 2017-12-02 01:15:11 -05:00
Ethan Buchman
388f66c9b3 types: drop uint64 from protobuf.go 2017-12-02 01:07:17 -05:00
Anton Kaliaev
cd5a5d332f remove comments for uint64 related to possible underflow [ci skip] 2017-12-01 23:30:08 -06:00
Ethan Buchman
cb9a1dbb4f p2p/trust: lock on Copy() 2017-12-01 23:35:17 -05:00
Ethan Buchman
814541f6d9 p2p/trust: split into multiple files and improve function order 2017-12-01 23:35:12 -05:00
Anton Kaliaev
89cbcceac4 error if app returned negative last block height (Fixes #911) 2017-12-01 21:56:08 -06:00
Anton Kaliaev
10f7858453 use rand.Int63n, remove underflow check, remove unnecessary cast 2017-12-01 19:22:18 -06:00
Anton Kaliaev
922af7c405 int64 height
uint64 is considered dangerous. the details will follow in a blog post.
2017-12-01 19:04:53 -06:00
Ethan Buchman
e9f8e56895 fixes from rebase 2017-12-01 17:25:44 -05:00
Anton Kaliaev
3eb069a50c no need in this hack since we have replay now 2017-12-01 17:17:22 -05:00
Anton Kaliaev
f1fbf995f7 protect ourselves again underflow (Refs #911) 2017-12-01 17:17:22 -05:00
Anton Kaliaev
86af889dfb remove unnecessary casts (Refs #911) 2017-12-01 17:17:22 -05:00
Anton Kaliaev
b3492356e6 uint64 height (Refs #911) 2017-12-01 17:17:22 -05:00
Ethan Buchman
b2489b4318 Merge pull request #912 from bluecollarcoding/fix/docs
docs:clarify py-abci/py-tendermint
2017-12-01 02:57:32 -05:00
Ethan Buchman
a5a7e7ac56 Merge pull request #913 from bluecollarcoding/zramsay-patch-1
codecov: ignore docs files
2017-12-01 02:56:34 -05:00
Ethan Buchman
74cbfc68a1 Merge pull request #835 from tendermint/feature/indexing
Indexing DeliverTx tags
2017-12-01 02:54:30 -05:00
Anton Kaliaev
6423306980 TestIndexAllTags (unit) 2017-11-30 23:02:40 -06:00
Anton Kaliaev
c5b62ce1ee correct abci version 2017-11-30 20:20:35 -06:00
Anton Kaliaev
e538e0e077 config variable to index all tags 2017-11-30 20:02:39 -06:00
Zach
9314e451c8 Update .codecov.yml 2017-11-30 19:01:50 +00:00
Zach Ramsay
3b61e2854a docs: correction, closes #910 2017-11-30 18:27:46 +00:00
Anton Kaliaev
03222d834b update abci dependency 2017-11-30 11:46:28 -06:00
Anton Kaliaev
cb9743e567 dummy app now returns one DeliverTx tag 2017-11-29 20:30:37 -06:00
Anton Kaliaev
66ad366a4f test searching for tx with multiple same tags 2017-11-29 20:04:26 -06:00
Anton Kaliaev
864ad8546e more test cases 2017-11-29 20:04:00 -06:00
Anton Kaliaev
58789c52cd add example for tx_search endpoint 2017-11-29 15:30:12 -06:00
Anton Kaliaev
a762253e24 do not use AddBatch, prefer copying for now 2017-11-29 15:25:12 -06:00
Anton Kaliaev
10d893ee9b update deps 2017-11-29 15:19:45 -06:00
Anton Kaliaev
acbc0717d4 add client methods 2017-11-29 15:19:44 -06:00
Anton Kaliaev
1e19860585 fixes from my own review 2017-11-29 14:24:18 -06:00
Anton Kaliaev
09941b9aa9 fix metalinter warnings 2017-11-29 14:24:18 -06:00
Anton Kaliaev
2a5e8c4a47 add minimal documentation for tx_search RPC method [ci skip] 2017-11-29 14:24:18 -06:00
Anton Kaliaev
686e0eea9f extract indexing goroutine to a separate indexer service 2017-11-29 14:24:18 -06:00
Anton Kaliaev
91f2184003 fixes after bucky's review 2017-11-29 14:24:18 -06:00
Anton Kaliaev
3e577ccf4f add tx_search RPC endpoint 2017-11-29 14:24:18 -06:00
Anton Kaliaev
ea0b205455 searching transaction results 2017-11-29 14:24:18 -06:00
Anton Kaliaev
16cf7a5e0a use a switch when validating tags 2017-11-29 14:23:44 -06:00
Anton Kaliaev
56abea7427 rename tm.events.type to just tm.event 2017-11-29 14:23:44 -06:00
Anton Kaliaev
461a143a2b remove tx.hash tag from config because it's mandatory 2017-11-29 14:23:44 -06:00
Anton Kaliaev
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
Anton Kaliaev
4a31532897 remove unreachable code 2017-11-29 14:23:44 -06:00
Anton Kaliaev
29cd1a1b8f rewrite indexer to be a listener of eventBus 2017-11-29 14:23:44 -06:00
Anton Kaliaev
cd4be1f308 add tx_index config 2017-11-29 14:23:43 -06:00
Anton Kaliaev
acae38ab9e validate tags 2017-11-29 14:23:43 -06:00
Anton Kaliaev
a52cdbfe43 extract tags from DeliverTx/Result
and send them along with predefined
2017-11-29 14:23:43 -06:00
Ethan Buchman
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
Anton Kaliaev
ceb8ba2e15 comment out gas linter for now 2017-11-29 13:18:34 -06:00
Ethan Buchman
aab54011b3 docs/install: add note about putting GOPATH/bin on PATH 2017-11-29 18:05:51 +00:00
Anton Kaliaev
691e266bef ignore ErrAlreadyStarted when starting addrbook in PEXReactor 2017-11-29 10:53:30 -06:00
Anton Kaliaev
c6b2334fa3 check for error when stopping WSClient 2017-11-29 10:38:58 -06:00
Anton Kaliaev
69b5da766c service#Start, service#Stop signatures were changed
See https://github.com/tendermint/tmlibs/issues/45
2017-11-29 10:38:58 -06:00
Ethan Buchman
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
Ethan Buchman
1b120466ee Merge pull request #892 from tendermint/mempool-Stop-method
mempool: implement Mempool.CloseWAL
2017-11-28 06:58:01 +00:00
Ethan Buchman
c8c533cc23 test/p2p/atomic_broadcast: wait for node heights before checking app hash 2017-11-28 05:51:32 +00:00
Ethan Buchman
1e8deacf2e Merge branch 'master' into develop 2017-11-28 04:39:41 +00:00
Emmanuel Odeke
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
Ethan Buchman
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
Adrian Brink
25f9eb782b Upgrade tmlibs dependency to build on Windows 2017-11-28 04:04:58 +00:00
Ethan Buchman
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
Zach
c3632bc54a Merge pull request #703 from tendermint/fix-linting
add metalinter to CI and include fixes
2017-11-28 00:02:52 +00:00
Ethan Buchman
d9c87a21a6 run metalinter in make test and run_test.sh 2017-11-27 22:39:12 +00:00
Ethan Buchman
2e76b23c9a rpc: fix tests 2017-11-27 22:39:12 +00:00
Ethan Buchman
9529f12c28 more linting 2017-11-27 22:39:12 +00:00
Ethan Buchman
55b81cc1a1 address linting FIXMEs 2017-11-27 22:39:12 +00:00
Zach Ramsay
c4caad7720 lint madness 2017-11-27 22:39:12 +00:00
Zach Ramsay
2563b4fc92 lint fixes 2017-11-27 22:39:12 +00:00
Zach Ramsay
6f3c05545d fix new linting errors 2017-11-27 22:39:12 +00:00
Zach Ramsay
414a8cb0ba pass tests! 2017-11-27 22:39:12 +00:00
Zach Ramsay
c84c7250ba linting: few more fixes 2017-11-27 22:39:12 +00:00
Zach Ramsay
c7b6faf96a bad goimports 2017-11-27 22:39:12 +00:00
Zach Ramsay
fe37afc0d7 do i need this? 2017-11-27 22:39:12 +00:00
Zach Ramsay
478a10aa41 Write doesn't need error checked 2017-11-27 22:39:12 +00:00
Zach Ramsay
d033470817 lil fixes 2017-11-27 22:39:12 +00:00
Zach Ramsay
7ad8a8ab55 Tests almost passing 2017-11-27 22:39:12 +00:00
Zach Ramsay
a15c7f221d linting: moar fixes 2017-11-27 22:39:11 +00:00
Zach Ramsay
d7cb291fb2 errcheck; sort some stuff out 2017-11-27 22:39:11 +00:00
Zach Ramsay
563faa98de address comments, pr #643 2017-11-27 22:39:11 +00:00
Zach Ramsay
9c62ed4595 run linting first for tests 2017-11-27 22:39:11 +00:00
Zach Ramsay
fe694e1fe1 ... 2017-11-27 22:39:11 +00:00
Zach Ramsay
bc2aa79f9a linter: sort through each kind and address small fixes 2017-11-27 22:39:11 +00:00
Zach Ramsay
48aca642e3 linter: address deadcode, implement incremental lint testing 2017-11-27 22:39:11 +00:00
Zach Ramsay
15651a931e linting errors: tackle p2p package 2017-11-27 22:39:11 +00:00
Zach Ramsay
68e7983c70 linting errors: afew more 2017-11-27 22:39:11 +00:00
Zach Ramsay
8f0237610e linting errors: clean it all up 2017-11-27 22:39:11 +00:00
Zach Ramsay
b75d4f73e7 errcheck: PR comment fixes 2017-11-27 22:39:11 +00:00
Zach Ramsay
b3c5933a23 state: return to-be-used function 2017-11-27 22:39:11 +00:00
Zach Ramsay
331857c9e6 linting: apply errcheck part2 2017-11-27 22:39:11 +00:00
Zach Ramsay
57ea4987f7 linting: apply errcheck part1 2017-11-27 22:39:11 +00:00
Zach Ramsay
d95ba866b8 lint: apply deadcode/unused 2017-11-27 22:39:11 +00:00
Zach Ramsay
1721543e5c linting: apply misspell 2017-11-27 22:39:11 +00:00
Zach Ramsay
46ccbcbff6 linting: apply 'gofmt -s -w' throughout 2017-11-27 22:39:11 +00:00
Zach Ramsay
fc33576bac linting: replace megacheck with metalinter 2017-11-27 22:39:11 +00:00
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
7dd249f754 Merge pull request #882 from caffix/develop
fixed race condition reported in issue #881
2017-11-27 16:50:57 +00:00
Adrian Brink
12ae1bb5e5 Address comments 2017-11-27 16:23:56 +01:00
Adrian Brink
248f176c1f Rename light to lite 2017-11-27 16:19:00 +01:00
Adrian Brink
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
Petabyte Storage
59b3dcb5cf normalize priority and id and remove pointers in ChannelDescriptor 2017-11-25 22:01:23 -08:00
Anton Kaliaev
fb87590c82 add Vagrant instructions to CONTRIBUTING guides (Refs #894) [ci skip] 2017-11-24 16:42:46 -06:00
Ethan Buchman
38c4de3fc7 Merge pull request #891 from tendermint/fix-vagrantfile
go requires Git (Fixes #879)
2017-11-24 22:07:29 +00:00
Anton Kaliaev
ae67408d13 go requires Git (Fixes #879) 2017-11-23 16:55:57 -06:00
Emmanuel Odeke
42da8cd297 consensus/WAL: benchmark WALDecode across data sizes 2017-11-23 12:43:11 -07:00
caffix
887cb6d0cd added public methods to handle locking within the trust metric 2017-11-22 23:42:38 -05:00
caffix
aeaf2d0b20 Merge branch 'develop' of https://github.com/tendermint/tendermint into develop 2017-11-22 23:11:01 -05:00
Ethan Buchman
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
Ethan Buchman
e845987503 p2p: disable trustmetric test while being fixed 2017-11-22 20:20:53 +00:00
Ethan Buchman
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
Ethan Buchman
52ad6242f4 Merge pull request #888 from tendermint/rm-dead-file
remove unused file
2017-11-22 18:47:30 +00:00
Zach Ramsay
969b34057b remove unused file 2017-11-22 17:22:53 +00:00
Petabyte Storage
e110f70b5c update glide.yaml versions with go-wire at develop branch 2017-11-22 07:34:10 -08:00
Ethan Buchman
e997db7a23 Merge pull request #859 from tendermint/fix/addrbook
Fix/addrbook
2017-11-21 15:31:48 +00:00
Ethan Buchman
c4b695f78d minor fixes from review 2017-11-21 15:30:19 +00:00
Ethan Buchman
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
A. F. Dudley
882c25f292 Update getting-started.rst to fix broken link
fixes broken link to introduction.html
2017-11-21 10:11:48 -05:00
caffix
9c8100043e made changes to address suggestions from the PR comments 2017-11-20 19:15:11 -05:00
Emmanuel Odeke
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
caffix
4087326f45 fixed race condition reported in issue #881 2017-11-20 16:47:05 -05:00
Ethan Buchman
f9bc22ec6a p2p: fix comment on addPeer (thanks @odeke-em) 2017-11-20 21:36:01 +00:00
Ethan Buchman
26cd99c66e p2p: fix non-routable addr in test 2017-11-20 19:56:44 +00:00
Ethan Buchman
9334aad906 Merge pull request #871 from tendermint/fix/docs-860
docs: fix links
2017-11-20 19:47:18 +00:00
Ethan Buchman
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
Martin Dyring-Andersen
5c4397ab30 Run tests on AppVeyor 2017-11-20 13:23:28 +01:00
Emmanuel Odeke
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
Zach Ramsay
559bd169bd docs: fix links, closes #860 2017-11-17 14:03:43 +00:00
Ethan Buchman
f8c969f5a5 Merge pull request #868 from tendermint/small-things
node: clean makeNodeInfo
2017-11-17 01:22:45 +00:00
Ethan Buchman
c5253c7a31 node: clean makeNodeInfo 2017-11-17 01:22:38 +00:00
Ethan Buchman
53f15fde07 update changelog 2017-11-17 00:04:03 +00:00
Ethan Buchman
814f9cb566 Merge pull request #856 from tendermint/small-things
Small things
2017-11-17 00:03:57 +00:00
Ethan Buchman
af0db599b0 minor fixes 2017-11-16 23:57:00 +00:00
Ethan Buchman
104368bd84 Merge pull request #787 from caffix/develop
Initial Trust Metric Implementation
2017-11-16 23:51:53 +00:00
Ethan Buchman
99461a178e Merge pull request #857 from gguoss/patch-1
Failed to compile comment code
2017-11-16 18:35:18 +00:00
Ethan Buchman
feb3230160 some comments 2017-11-16 04:43:07 +00:00
Ethan Buchman
be1a16a601 p2p/pex: simplify ensurePeers 2017-11-16 04:30:38 +00:00
Ethan Buchman
8e044b0e6d p2p/addrbook: some comments 2017-11-16 04:30:23 +00:00
Ethan Buchman
40e93a5f9e p2p/addrbook: fix addToOldBucket 2017-11-16 04:08:46 +00:00
Ethan Buchman
435eb6e2b3 p2p/addrbook: add non-terminating test 2017-11-16 04:04:54 +00:00
Ethan Buchman
8c88cc017a p2p/addrbook: addAddress returns error. more defensive PickAddress 2017-11-16 03:59:54 +00:00
Ethan Buchman
ed95cc160a p2p/addrbook: simplify PickAddress 2017-11-16 02:31:47 +00:00
Ethan Buchman
2f067a3f65 p2p/addrbook: addrNew/Old -> bucketsNew/Old 2017-11-16 02:28:11 +00:00
Ethan Buchman
498a82784d p2p/addrbook: comments 2017-11-16 02:25:00 +00:00
Guanghua Guo
b5708825a7 Failed to compile comment code 2017-11-16 09:45:58 +08:00
caffix
a724ffab25 added changes based on PR comments to the proposal 2017-11-15 17:59:48 -05:00
Ethan Buchman
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
Anton Kaliaev
248a9383a0 add Go version badge to README [ci skip] 2017-11-15 10:22:02 -06:00
Ethan Buchman
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
Emmanuel Odeke
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
Ethan Buchman
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
Emmanuel Odeke
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
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
0cd642bca7 Merge pull request #849 from tendermint/846-fix-TestFullRound1-race
fix TestFullRound1 race (Refs #846)
2017-11-15 03:27:59 +00:00
Anton Kaliaev
fe3c92ecce unescape $NODE_FLAGS (see comment) 2017-11-14 20:56:39 -06:00
Ethan Buchman
a969e24177 crank context timeouts 2017-11-15 01:42:15 +00:00
Emmanuel Odeke
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
Anton Kaliaev
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
caffix
8b7649b90c enhancements made in response to PR full review comments 2017-11-14 18:26:06 -05:00
caffix
687834c99e added initial trust metric test routines 2017-11-14 18:26:06 -05:00
caffix
54c25ccbf5 integrated trust metric store as per PR comments 2017-11-14 18:26:06 -05:00
caffix
e160a6198c added initial trust metric design doc and code 2017-11-14 18:26:06 -05:00
Ethan Buchman
e69d36d54f some more robust sleeps 2017-11-14 22:31:23 +00:00
Ethan Buchman
844c43e044 use stdlib context 2017-11-14 22:30:00 +00:00
Ethan Buchman
194712fd3b rpc: wait for rpc servers to be available in tests 2017-11-14 21:51:49 +00:00
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
3db44dacae Merge pull request #840 from tendermint/fix/tests
Fix/tests
2017-11-14 15:48:17 +00:00
Emmanuel Odeke
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
Petabyte Storage
3863885c71 WIP: begin parallel refactoring with go-wire Write methods and MConnection 2017-11-12 22:11:15 -08:00
Ethan Buchman
238e2b72ee Merge pull request #834 from tendermint/829-enable-logs-by-default
Enable logs by default
2017-11-12 07:06:14 +00:00
Ethan Buchman
a65ab3b0e0 Merge pull request #838 from tendermint/docker
docker update || 0.12.0
2017-11-12 06:51:01 +00:00
Ethan Buchman
aba8a8f4fc consensus: crank timeout in timeoutWaitGroup 2017-11-12 06:41:15 +00:00
Ethan Buchman
0448c2b437 consensus: fix LastCommit log 2017-11-12 06:40:27 +00:00
Ethan Buchman
0ada0cf525 certifiers: test uses WaitForHeight 2017-11-12 00:43:16 +00:00
Anton Kaliaev
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
Anton Kaliaev
bc9c4e8dee update readme [ci skip] 2017-11-10 15:38:32 -05:00
Anton Kaliaev
8004af2519 update docker readme 2017-11-10 15:17:13 -05:00
Anton Kaliaev
21e87ebc11 update Go version to 1.9.2 2017-11-10 15:10:52 -05:00
Anton Kaliaev
70d8afa6e9 update Dockerfile 2017-11-10 15:09:38 -05:00
Ethan Buchman
847f865438 Merge pull request #836 from tendermint/fix/tests
consensus: make mempool_test deterministic
2017-11-10 05:08:54 +00:00
Ethan Buchman
2cda777900 consensus: make mempool_test deterministic 2017-11-09 23:54:02 +00:00
Anton Kaliaev
432a7276e2 [test_integrations] enable logs from peers by default (Refs #829) 2017-11-09 15:19:49 -05:00
Anton Kaliaev
533f7c45eb fix bash linter warnings for atomic_broadcast integration test 2017-11-09 14:58:16 -05:00
Anton Kaliaev
a1cdc2b68a set logger for peer's MConnection 2017-11-09 14:57:40 -05:00
Ethan Buchman
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
Anton Kaliaev
ad03491ee6 remove duplicated key 2017-11-09 13:37:29 -05:00
Ethan Buchman
4b9dfc8990 consensus: fix for initializing block parts during catchup 2017-11-09 18:14:41 +00:00
Ethan Buchman
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
Anton Kaliaev
b1e7163689 rewrite node test to use new pubsub 2017-11-08 13:12:48 -05:00
Ethan Buchman
c931279960 p2p: some fixes re @odeke-em issues #813,#816,#817 2017-11-08 17:54:29 +00:00
Ethan Buchman
12b25fdf6e blockchain: add comment in AddPeer. closes #666 2017-11-08 02:42:27 +00:00
Ethan Buchman
c0e2649ed6 Merge pull request #788 from tendermint/feature/548-indexing-tags
new pubsub package
2017-11-08 01:02:48 +00:00
Ethan Buchman
593c127257 rpc/lib/types: RPCResponse.Result is not a pointer 2017-11-08 01:00:15 +00:00
Ethan Buchman
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
Ethan Buchman
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
Anton Kaliaev
a01c226dc4 wsConnection: call onDisconnect 2017-11-07 19:22:01 -05:00
Ethan Buchman
47f5e37205 copy RoundState for event 2017-11-07 23:57:23 +00:00
Petabyte Storage
51c9211cf4 add test for MConnection TrySend and Send 2017-11-07 23:35:25 +00:00
Anton Kaliaev
7869e541f6 change MakeConnectedSwitches to not connect to itself
and a test for it
2017-11-07 18:33:00 -05:00
Anton Kaliaev
e0daca5693 fixes from Bucky's review 2017-11-07 18:20:24 -05:00
Ethan Buchman
e8e512f1fa Merge pull request #815 from tendermint/p2p-readme-tests
P2P: readme and tests
2017-11-07 23:01:15 +00:00
Ethan Buchman
37ce171061 p2p/connetion: remove panics, test error cases 2017-11-07 23:00:52 +00:00
Ethan Buchman
e01986e2b3 p2p: update readme, some minor things 2017-11-07 23:00:49 +00:00
Ethan Buchman
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
Anton Kaliaev
2d4ad02356 prefer tickers to time.Sleep (Refs #790) 2017-11-07 15:38:25 -05:00
Ethan Buchman
3b81d3fea4 consensus: ensure prs.ProposalBlockParts is initialized. fixes #810 2017-11-07 17:14:40 +00:00
Anton Kaliaev
e785697a64 connect first switch to others (Refs #808) 2017-11-06 23:43:40 -05:00
Anton Kaliaev
4ffe9304ba unsubscribe from all subscriptions on WS disconnect 2017-11-02 14:00:18 -05:00
Anton Kaliaev
b1eec3a5d3 remove test_data/empty_block and test_data/small_blockN 2017-11-02 13:20:14 -05:00
Anton Kaliaev
fcdd30b2d3 fixes from Bucky's review 2 2017-11-02 13:20:05 -05:00
Ethan Buchman
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
Ethan Buchman
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
Ethan Buchman
f7f4ba5e90 rpc/lib/server: minor changes to test 2017-10-31 15:41:25 -04:00
Ethan Buchman
5466720d75 minor changes from @odeke-em PR #725 2017-10-31 15:32:07 -04:00
Ethan Buchman
7c3cf316f1 rpc/wsevents: small cleanup 2017-10-31 15:16:08 -04:00
Ethan Buchman
d71aed309f some minor changes 2017-10-30 22:52:03 -04:00
Ethan Buchman
d6beb60bf7 Merge pull request #799 from petabytestorage/fix-typo-switch-comment
fix comment typos
2017-10-30 18:01:32 -04:00
Anton Kaliaev
61d76a273f fixes from Bucky's and Emmanuel's reviews 2017-10-30 11:12:01 -05:00
Anton Kaliaev
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
Anton Kaliaev
1c1c68df8d fixes from my own review 2017-10-30 00:32:23 -05:00
Anton Kaliaev
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
Petabyte Storage
fe9ff62297 fix comment typos 2017-10-28 22:01:45 -07:00
Ethan Buchman
7c85f15a6c Merge pull request #798 from petabytestorage/fix-test-uncommon-names
fix test using uncommon names
2017-10-28 23:47:31 -04:00
Petabyte Storage
6b366b2443 fix test using uncommon names 2017-10-28 20:29:11 -07:00
Emmanuel Odeke
a8b77359df rpc/lib/server: separate out Notifications test
Addressing feedback from @ebuchman
2017-10-28 15:24:40 -07:00
Emmanuel Odeke
e7fab7d4bf rpc/lib/server: update with @melekes and @ebuchman feedback 2017-10-28 15:11:21 -07:00
Emmanuel Odeke
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
Ethan Buchman
128e2a1d9e Merge branch 'master' into develop 2017-10-28 00:09:03 -04:00
Ethan Buchman
e236302256 Merge pull request #793 from tendermint/release-v0.12.0
Release v0.12.0
2017-10-28 00:06:53 -04:00
Ethan Buchman
dfe28c8855 test: update for abci-cli consolidation. shell formatting 2017-10-27 23:09:50 -04:00
Ethan Buchman
4b616344fa update glide, again 2017-10-27 22:36:03 -04:00
Ethan Buchman
1ecd580061 Merge pull request #773 from tendermint/docs-staging
docs improvements
2017-10-27 16:18:56 -04:00
Ethan Buchman
21dcb4f290 update glide 2017-10-27 13:55:56 -04:00
Ethan Buchman
b2b35d7dc1 update changelog 2017-10-27 11:54:20 -04:00
Ethan Buchman
a1501dcde8 version bump 2017-10-27 11:54:20 -04:00
Ethan Buchman
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
Ethan Buchman
fe1c60b5cf consensus: kill process on app error 2017-10-27 10:55:20 -04:00
Ethan Buchman
591dd9e662 dont catchupReplay on wal if we fast synced 2017-10-27 10:46:19 -04:00
Ethan Buchman
bb6c15b00a CHANGELOG [ci skip] 2017-10-26 09:42:46 -04:00
Ethan Buchman
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
Ethan Buchman
fcf459158d CHANGELOG [ci skip] 2017-10-26 00:29:58 -04:00
Ethan Buchman
e76ef2a8a1 types: unexpose valset.To/FromBytes 2017-10-26 00:27:02 -04:00
Ethan Buchman
3c92bea519 glide: more external deps locked to versions 2017-10-26 00:07:43 -04:00
Ethan Buchman
12c703c1c3 Merge branch 'develop' into 573-wal-issues 2017-10-25 23:56:08 -04:00
Ethan Buchman
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
Petabyte Storage
ceedd4d968 remove unnecessary plus [ci skip] 2017-10-25 22:28:20 -04:00
Ethan Buchman
c595636999 glide 2017-10-25 22:23:55 -04:00
Emmanuel Odeke
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
Ethan Buchman
57a684d5ac fixes from review 2017-10-25 21:54:56 -04:00
Ethan Buchman
5534eb4707 Merge pull request #776 from tendermint/feature/merge-light-client
Merge light client
2017-10-25 16:12:39 -04:00
Ethan Buchman
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
Ethan Frey
f653ba63bf Separated out certifiers.Commit from rpc structs 2017-10-25 16:43:18 +02:00
Ethan Frey
0396b6d521 Rename checkpoint.go 2017-10-25 16:13:04 +02:00
Ethan Frey
94b36bb65e Move VerifyCommitAny into the types package 2017-10-25 16:13:04 +02:00
Ethan Frey
b4fd6e876e Copy certifiers from light-client 2017-10-25 16:13:04 +02:00
Ethan Buchman
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
Silas Davis
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
Anton Kaliaev
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
Ethan Buchman
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
Eric Mann
45e18a1832 Change log level to Info when proposal block hashing fails due to partially complete block 2017-10-24 14:13:35 -07:00
Silas Davis
f6adddb4a8 Replace ResultsCh with ResponsesCh 2017-10-24 17:45:13 +01:00
Ethan Buchman
38fc351532 Merge pull request #765 from tendermint/762-blockchain-reactor-timeout
blockchain reactor timeout
2017-10-24 09:13:26 -04:00
Silas Davis
01be6fa309 Fix WSClient blocking in the readRoutine after Stop() as it tries to write to ResultsCh 2017-10-24 13:31:24 +01:00
Anton Kaliaev
e06bbaf303 refactor TestNoBlockMessageResponse to eliminate a race condition 2017-10-24 15:32:01 +04:00
Anton Kaliaev
bb7b152af5 write docs for cutWALUntil and wal2json binaries 2017-10-24 13:25:47 +04:00
Emmanuel Odeke
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
Anton Kaliaev
c74a359c46 fixes per Bucky's review 2017-10-24 12:14:21 +04:00
Zach Ramsay
ee9dc6ce59 docs: fixup abci guide 2017-10-23 20:56:49 -04:00
Zach Ramsay
62e8ec34d1 fix comment, #723 2017-10-23 19:51:09 -04:00
Matt Bell
6a5254c475 Added local blockchain sync benchmark script 2017-10-23 19:46:57 -04:00
Ethan Buchman
2802a06a08 blockchain/store: comment about panics 2017-10-23 19:46:14 -04:00
Zach
8ac430813d Merge pull request #772 from tendermint/docs/flow
moar docs updates
2017-10-23 19:14:06 -04:00
Zach Ramsay
3e61b8c17a docs: comb through step by step 2017-10-23 19:11:51 -04:00
Zach Ramsay
9e277d1596 docs: smaller logo (200px) 2017-10-23 17:34:27 -04:00
Zach
4c9d5244a5 Merge pull request #759 from tendermint/improve-docs
docs: update abci example details
2017-10-23 17:29:34 -04:00
Ethan Buchman
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
Anton Kaliaev
3115c23762 binary format for WAL 2017-10-23 22:27:24 +04:00
Anton Kaliaev
31030c6514 make crc32c a global var
change echo format in build.sh script
2017-10-23 22:09:42 +04:00
Anton Kaliaev
7b8ffc9981 add checksum and msg size to TimedWALMessage
updated test_data/build.sh script
2017-10-23 22:09:17 +04:00
Ethan Buchman
a75bccfbc4 Merge branch 'develop' into 564-add-app-options-to-genesis-resp 2017-10-23 11:30:00 -04:00
Ethan Buchman
f97229f05a Merge pull request #748 from tendermint/params-test
types: ConsensusParams test + document the ranges/limits
2017-10-23 11:18:00 -04:00
Ethan Buchman
ac2ef9e0ea Merge pull request #750 from tendermint/feature/cleanup
Cleanup of code and code docs
2017-10-23 11:14:15 -04:00
Ethan Buchman
c2803b80e8 update changelog; fixes from rebase 2017-10-23 11:13:12 -04:00
Ethan Buchman
7a6876bc62 Merge pull request #768 from tendermint/feature/merkleeyes-to-iavl
Feature/merkleeyes to iavl
2017-10-23 11:07:21 -04:00
Adrian Brink
819f81f702 Change NOTE to CONTRACT 2017-10-23 11:04:45 -04:00
Adrian Brink
036d3b59a3 Address reviews 2017-10-23 11:04:45 -04:00
Adrian Brink
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
Ethan Buchman
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
Anton Kaliaev
f908dd0e55 only notify when there are some txs (Refs #753) 2017-10-23 10:31:00 -04:00
Ethan Buchman
0bbf38141a blockchain/pool: some comments and small changes 2017-10-23 10:13:46 -04:00
Ethan Buchman
f188366e26 update glide 2017-10-23 10:04:00 -04:00
Ethan Buchman
fd60621a8e update cswal test 2017-10-23 10:03:54 -04:00
Ethan Buchman
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
Silas Davis
3e3d53daef Make RPCError an actual error and don't swallow its companion data 2017-10-22 15:14:21 +01:00
Anton Kaliaev
d64a48e0ee set logger on blockchain pool 2017-10-20 23:56:21 +04:00
Anton Kaliaev
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
Zach Ramsay
8a69f1087b docs: typo 2017-10-20 07:56:26 -04:00
Emmanuel Odeke
f24f03906f types: ConsensusParams: add feedback from @ebuchman and @melekes 2017-10-20 00:11:30 -06:00
Ethan Buchman
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
Zach Ramsay
fc406d1657 docs: update abci example details [ci skip] 2017-10-18 16:33:37 -04:00
Zach
9dcefd0e1e Merge pull request #754 from tendermint/improve-docs
add tm-migrator to docs
2017-10-18 13:04:12 -04:00
Zach
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
Anton Kaliaev
b9c4fab96e correct an error in validator's specification [ci skip] (Refs #756) 2017-10-18 19:23:30 +04:00
Zach Ramsay
fa07dbd7ec docs: add info about tm-migrate 2017-10-18 08:47:58 -04:00
Zach Ramsay
9b382d7a11 docs: remove mention of type byte 2017-10-18 08:00:01 -04:00
Anton Kaliaev
75b78bfb72 panic on marshal/unmarshal failures for genesisDoc 2017-10-17 13:33:57 +04:00
Ethan Buchman
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
Emmanuel Odeke
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
Anton Kaliaev
616b07ff6b make AppOptions an interface{} 2017-10-16 10:58:52 +04:00
Anton Kaliaev
b26f812399 update changelog 2017-10-16 10:58:52 +04:00
Anton Kaliaev
321061125f add app_options to GenesisDoc (Refs #564) 2017-10-16 10:58:52 +04:00
Anton Kaliaev
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
Anton Kaliaev
c4646bf87f make state#Params not a pointer
also remove the comment
2017-10-16 10:34:02 +04:00
Anton Kaliaev
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
Anton Kaliaev
1971e149fb ChainID() and Params() do not return errors
- remove state#GenesisDoc() method
2017-10-16 10:34:02 +04:00
Emmanuel Odeke
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
Zach
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
Zach
09170f76fe Merge pull request #743 from tendermint/zramsay-patch-1
Update getting-started.rst
2017-10-15 11:01:19 -04:00
srmo
9e1edf8685 [docs] add Java examples for each section 2017-10-15 13:45:43 +02:00
srmo
e7fe299504 [docs] replace all GO snippets with collapsible blocks 2017-10-15 12:21:06 +02:00
srmo
b90edffe28 [docs] add first java block for deliverTx 2017-10-15 12:00:08 +02:00
srmo
f361092ed9 [docs] provide means to have collapsible code blocks without adding a new theme 2017-10-15 11:59:37 +02:00
Ethan Buchman
a1e0f0ba95 docs/ecosystem: add py-tendermint to abci-servers 2017-10-14 00:59:34 -04:00
Emmanuel Odeke
5f218a43fd rpc/client: use compile time assertions instead of methods 2017-10-13 14:30:54 -06:00
Zach
7fe470fc76 Update getting-started.rst 2017-10-13 14:50:54 -04:00
Ethan Buchman
d490c25807 Merge pull request #720 from tendermint/types-heartbeat-test
types/heartbeat: test all Heartbeat functions
2017-10-13 09:22:59 -04:00
Ethan Buchman
340f33b475 Merge pull request #734 from tendermint/482-support-historical-abci-queries
support historical abci queries
2017-10-13 09:14:32 -04:00
Anton Kaliaev
7518c4a9be [rpc] update comment [ci skip] 2017-10-13 15:03:21 +04:00
Anton Kaliaev
db413aadfd fixes from @cloudhead review 2017-10-13 15:03:21 +04:00
Anton Kaliaev
5433e5771e support historical abci queries (Refs #482) 2017-10-13 15:03:20 +04:00
Zach Ramsay
e2e50bc0fc rpc: use /iavl repo in test (#713) 2017-10-11 10:35:22 -04:00
Ethan Buchman
27245ce6f6 Merge branch 'master' into develop 2017-10-10 19:12:40 -04:00
Ethan Buchman
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
Ethan Buchman
0011af7adf Merge pull request #727 from sbellem/docs-typo-fix
[docs:typo fix] remove misplaced "the"
2017-10-10 11:20:34 -04:00
Sylvain Bellemare
1764106606 [docs: typo fix] add missing "have" 2017-10-10 17:15:35 +02:00
Sylvain Bellemare
8219abc552 [docs:typo fix] remove misplaced "the" 2017-10-09 20:06:43 +02:00
Emmanuel Odeke
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
551 changed files with 43117 additions and 13723 deletions

220
.circleci/config.yml Normal file
View File

@@ -0,0 +1,220 @@
version: 2
defaults: &defaults
working_directory: /go/src/github.com/tendermint/tendermint
docker:
- image: circleci/golang:1.10.3
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:
- v2-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: v2-pkg-cache
paths:
- /go/pkg
- save_cache:
key: v2-tree-{{ .Environment.CIRCLE_SHA1 }}
paths:
- /go/src/github.com/tendermint/tendermint
setup_abci:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v2-pkg-cache
- restore_cache:
key: v2-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*"
build_slate:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v2-pkg-cache
- restore_cache:
key: v2-tree-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: slate docs
command: |
set -ex
export PATH="$GOBIN:$PATH"
make build-slate
lint:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v2-pkg-cache
- restore_cache:
key: v2-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: v2-pkg-cache
- restore_cache:
key: v2-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: v2-pkg-cache
- restore_cache:
key: v2-tree-{{ .Environment.CIRCLE_SHA1 }}
- run: mkdir -p /tmp/logs
- 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")
GOCACHE=off go test -v -timeout 5m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" | tee "/tmp/logs/$id-$RANDOM.log"
done
- persist_to_workspace:
root: /tmp/workspace
paths:
- "profiles/*"
- store_artifacts:
path: /tmp/logs
test_persistence:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v2-pkg-cache
- restore_cache:
key: v2-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/p2p/circleci.sh
upload_coverage:
<<: *defaults
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v2-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,10 +8,7 @@ end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[Makefile]
indent_style = tab
[*.sh]
[*.{sh,Makefile}]
indent_style = tab
[*.proto]

5
.github/CODEOWNERS vendored
View File

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

View File

@@ -19,10 +19,6 @@ in a case of bug.
**ABCI app** (name for built-in, URL for self-written if it's publicly available):
**Merkleeyes version** (use `git rev-parse --verify HEAD`, skip if you don't use it):
**Environment**:
- **OS** (e.g. from /etc/os-release):
- **Install tools**:
@@ -37,5 +33,10 @@ 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)**:
**Config (you can paste only the changes you've made)**:
**`/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

12
.gitignore vendored
View File

@@ -5,7 +5,6 @@
.DS_Store
build/*
rpc/test/.tendermint
.debora
.tendermint
remote_dump
.revision
@@ -13,7 +12,16 @@ vendor
.vagrant
test/p2p/data/
test/logs
.glide
coverage.txt
docs/_build
docs/tools
docs/abci-spec.md
*.log
scripts/wal2json/wal2json
scripts/cutWALUntil/cutWALUntil
.idea/
*.iml
libs/pubsub/query/fuzz_test/output

View File

@@ -1,32 +1,445 @@
# Changelog
## Roadmap
## 0.21.0
BREAKING CHANGES:
- Upgrade the header to support better proofs on validtors, results, evidence, and possibly more
- Better support for injecting randomness
- Pass evidence/voteInfo through ABCI
- Upgrade consensus for more real-time use of evidence
*June 21th, 2018*
FEATURES:
- Peer reputation management
- 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)
- Improved support for querying history and state
- Add authentication and rate-limitting to the RPC
BREAKING CHANGES
- [config] Change default ports from 4665X to 2665X. Ports over 32768 are
ephemeral and reserved for use by the kernel.
- [cmd] `unsafe_reset_all` removes the addrbook.json
IMPROVEMENT
- [pubsub] Set default capacity to 0
- [docs] Various improvements
BUG FIXES
- [consensus] Fix an issue where we don't make blocks after `fast_sync` when `create_empty_blocks=false`
- [mempool] Fix #1761 where we don't process txs if `cache_size=0`
- [rpc] Fix memory leak in Websocket (when using `/subscribe` method)
- [config] Escape paths in config - fixes config paths on Windows
## 0.20.0
*June 6th, 2018*
This is the first in a series of breaking releases coming to Tendermint after
soliciting developer feedback and conducting security audits.
This release does not break any blockchain data structures or
protocols other than the ABCI messages between Tendermint and the application.
Applications that upgrade for ABCI v0.11.0 should be able to continue running Tendermint
v0.20.0 on blockchains created with v0.19.X
BREAKING CHANGES
- [abci] Upgrade to
[v0.11.0](https://github.com/tendermint/abci/blob/master/CHANGELOG.md#0110)
- [abci] Change Query path for filtering peers by node ID from
`p2p/filter/pubkey/<id>` to `p2p/filter/id/<id>`
## 0.19.9
*June 5th, 2018*
BREAKING CHANGES
- [types/priv_validator] Moved to top level `privval` package
FEATURES
- [config] Collapse PeerConfig into P2PConfig
- [docs] Add quick-install script
- [docs/spec] Add table of Amino prefixes
BUG FIXES
- [rpc] Return 404 for unknown endpoints
- [consensus] Flush WAL on stop
- [evidence] Don't send evidence to peers that are behind
- [p2p] Fix memory leak on peer disconnects
- [rpc] Fix panic when `per_page=0`
## 0.19.8
*June 4th, 2018*
BREAKING:
- [p2p] Remove `auth_enc` config option, peer connections are always auth
encrypted. Technically a breaking change but seems no one was using it and
arguably a bug fix :)
BUG FIXES
- [mempool] Fix deadlock under high load when `skip_timeout_commit=true` and
`create_empty_blocks=false`
## 0.19.7
*May 31st, 2018*
BREAKING:
- [libs/pubsub] TagMap#Get returns a string value
- [libs/pubsub] NewTagMap accepts a map of strings
FEATURES
- [rpc] the RPC documentation is now published to https://tendermint.github.io/slate
- [p2p] AllowDuplicateIP config option to refuse connections from same IP.
- true by default for now, false by default in next breaking release
- [docs] Add docs for query, tx indexing, events, pubsub
- [docs] Add some notes about running Tendermint in production
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
- [consensus] Consensus reactor now receives events from a separate synchronous event bus,
which is not dependant on external RPC load
- [consensus/wal] do not look for height in older files if we've seen height - 1
- [docs] Various cleanup and link fixes
## 0.19.6
*May 29th, 2018*
BUG FIXES
- [blockchain] Fix fast-sync deadlock during high peer turnover
BUG FIX:
- [evidence] Dont send peers evidence from heights they haven't synced to yet
- [p2p] Refuse connections to more than one peer with the same IP
- [docs] Various fixes
## 0.19.5
*May 20th, 2018*
BREAKING CHANGES
- [rpc/client] TxSearch and UnconfirmedTxs have new arguments (see below)
- [rpc/client] TxSearch returns ResultTxSearch
- [version] Breaking changes to Go APIs will not be reflected in breaking
version change, but will be included in changelog.
FEATURES
- [rpc] `/tx_search` takes `page` (starts at 1) and `per_page` (max 100, default 30) args to paginate results
- [rpc] `/unconfirmed_txs` takes `limit` (max 100, default 30) arg to limit the output
- [config] `mempool.size` and `mempool.cache_size` options
IMPROVEMENTS
- [docs] Lots of updates
- [consensus] Only Fsync() the WAL before executing msgs from ourselves
BUG FIXES
- [mempool] Enforce upper bound on number of transactions
## 0.19.4 (May 17th, 2018)
IMPROVEMENTS
- [state] Improve tx indexing by using batches
- [consensus, state] Improve logging (more consensus logs, fewer tx logs)
- [spec] Moved to `docs/spec` (TODO cleanup the rest of the docs ...)
BUG FIXES
- [consensus] Fix issue #1575 where a late proposer can get stuck
## 0.19.3 (May 14th, 2018)
FEATURES
- [rpc] New `/consensus_state` returns just the votes seen at the current height
IMPROVEMENTS
- [rpc] Add stringified votes and fraction of power voted to `/dump_consensus_state`
- [rpc] Add PeerStateStats to `/dump_consensus_state`
BUG FIXES
- [cmd] Set GenesisTime during `tendermint init`
- [consensus] fix ValidBlock rules
## 0.19.2 (April 30th, 2018)
FEATURES:
- [p2p] Allow peers with different Minor versions to connect
- [rpc] `/net_info` includes `n_peers`
IMPROVEMENTS:
- [p2p] Various code comments, cleanup, error types
- [p2p] Change some Error logs to Debug
BUG FIXES:
- Graceful handling/recovery for apps that have non-determinism or fail to halt
- Graceful handling/recovery for violations of safety, or liveness
- [p2p] Fix reconnect to persistent peer when first dial fails
- [p2p] Validate NodeInfo.ListenAddr
- [p2p] Only allow (MaxNumPeers - MaxNumOutboundPeers) inbound peers
- [p2p/pex] Limit max msg size to 64kB
- [p2p] Fix panic when pex=false
- [p2p] Allow multiple IPs per ID in AddrBook
- [p2p] Fix before/after bugs in addrbook isBad()
## 0.19.1 (April 27th, 2018)
Note this release includes some small breaking changes in the RPC and one in the
config that are really bug fixes. v0.19.1 will work with existing chains, and make Tendermint
easier to use and debug. With <3
BREAKING (MINOR)
- [config] Removed `wal_light` setting. If you really needed this, let us know
FEATURES:
- [networks] moved in tooling from devops repo: terraform and ansible scripts for deploying testnets !
- [cmd] Added `gen_node_key` command
BUG FIXES
Some of these are breaking in the RPC response, but they're really bugs!
- [spec] Document address format and pubkey encoding pre and post Amino
- [rpc] Lower case JSON field names
- [rpc] Fix missing entries, improve, and lower case the fields in `/dump_consensus_state`
- [rpc] Fix NodeInfo.Channels format to hex
- [rpc] Add Validator address to `/status`
- [rpc] Fix `prove` in ABCIQuery
- [cmd] MarshalJSONIndent on init
## 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
- [test] docker-compose for local testnet setup (thanks Greg!)
## 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)

View File

@@ -8,9 +8,9 @@ Please make sure to use `gofmt` before every commit - the easiest way to do this
## Forking
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`.
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.
@@ -34,16 +34,44 @@ Please don't make Pull Requests to `master`.
## Dependencies
We use [glide](https://github.com/masterminds/glide) 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 `glide install`. Even for dependencies under our control, glide helps us keeps multiple repos in sync as they evolve. Anything with an executable, such as apps, tools, and the core, should use glide.
We use [dep](https://github.com/golang/dep) to manage dependencies.
Run `bash scripts/glide/status.sh` to get a list of vendored dependencies that may not be up-to-date.
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 circle.
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`.
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
@@ -75,3 +103,15 @@ especially `go-p2p` and `go-rpc`, as their versions are referenced in tendermint
- 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

1
DOCKER/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
tendermint

View File

@@ -1,45 +1,39 @@
FROM alpine:3.6
FROM alpine:3.7
MAINTAINER Greg Szabo <greg@tendermint.com>
# This is the release of tendermint to pull in.
ENV TM_VERSION 0.11.0
ENV TM_SHA256SUM 7e443bac4d42f12e7beaf9cee63b4a565dad8c58895291fdedde8057088b70c5
# 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
# validator file into /tendermint.
# Tendermint will be looking for the genesis file in /tendermint/config/genesis.json
# (unless you change `genesis_file` in config.toml). You can put your config.toml and
# private validator file into /tendermint/config.
#
# The /tendermint/data dir is used by tendermint to store state.
ENV DATA_ROOT /tendermint
ENV TMHOME $DATA_ROOT
# Set user right away for determinism
RUN addgroup tmuser && \
adduser -S -G tmuser tmuser
# Create directory for persistence and give our user ownership
RUN mkdir -p $DATA_ROOT && \
chown -R tmuser:tmuser $DATA_ROOT
ENV TMHOME /tendermint
# OS environment setup
# Set user right away for determinism, create directory for persistence and give our user ownership
# jq and curl used for extracting `pub_key` from private validator while
# deploying tendermint with Kubernetes. It is nice to have bash so the users
# could execute bash commands.
RUN apk add --no-cache bash curl jq
RUN apk update && \
apk upgrade && \
apk --no-cache add curl jq bash && \
addgroup tmuser && \
adduser -S -G tmuser tmuser -h "$TMHOME"
RUN apk add --no-cache openssl && \
wget https://s3-us-west-2.amazonaws.com/tendermint/binaries/tendermint/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 && \
rm -f tendermint_${TM_VERSION}_linux_amd64.zip
# Run the container with tmuser by default. (UID=100, GID=1000)
USER tmuser
# Expose the data directory as a volume since there's mutable state in there
VOLUME $DATA_ROOT
VOLUME [ $TMHOME ]
# p2p port
EXPOSE 46656
# rpc port
EXPOSE 46657
WORKDIR $TMHOME
ENTRYPOINT ["tendermint"]
# p2p and rpc port
EXPOSE 26656 26657
ENTRYPOINT ["/usr/bin/tendermint"]
CMD ["node", "--moniker=`hostname`"]
STOPSIGNAL SIGTERM
ARG BINARY=tendermint
COPY $BINARY /usr/bin/tendermint

View File

@@ -1,4 +1,4 @@
FROM alpine:3.6
FROM alpine:3.7
ENV DATA_ROOT /tendermint
ENV TMHOME $DATA_ROOT
@@ -18,18 +18,18 @@ 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
VOLUME $DATA_ROOT
EXPOSE 46656
EXPOSE 46657
EXPOSE 26656
EXPOSE 26657
ENTRYPOINT ["tendermint"]
CMD ["node", "--moniker=`hostname`", "--proxy_app=dummy"]
CMD ["node", "--moniker=`hostname`", "--proxy_app=kvstore"]

18
DOCKER/Dockerfile.testing Normal file
View File

@@ -0,0 +1,18 @@
FROM golang:1.10.1
# Grab deps (jq, hexdump, xxd, killall)
RUN apt-get update && \
apt-get install -y --no-install-recommends \
jq bsdmainutils vim-common psmisc netcat
# Add testing deps for curl
RUN echo 'deb http://httpredir.debian.org/debian testing main non-free contrib' >> /etc/apt/sources.list && \
apt-get update && \
apt-get install -y --no-install-recommends curl
VOLUME /go
EXPOSE 26656
EXPOSE 26657

View File

@@ -7,6 +7,9 @@ push:
build_develop:
docker build -t "tendermint/tendermint:develop" -f Dockerfile.develop .
build_testing:
docker build --tag tendermint/testing -f ./Dockerfile.testing .
push_develop:
docker push "tendermint/tendermint:develop"

View File

@@ -1,6 +1,13 @@
# Supported tags and respective `Dockerfile` links
# Docker
- `0.11.0`, `latest` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/9177cc1f64ca88a4a0243c5d1773d10fba67e201/DOCKER/Dockerfile)
## Supported tags and respective `Dockerfile` links
- `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)
@@ -9,10 +16,10 @@
`develop` tag points to the [develop](https://github.com/tendermint/tendermint/tree/develop) branch.
# Quick reference
## Quick reference
* **Where to get help:**
[Chat on Rocket](https://cosmos.rocket.chat/)
https://cosmos.network/community
* **Where to file issues:**
https://github.com/tendermint/tendermint/issues
@@ -20,7 +27,7 @@
* **Supported Docker versions:**
[the latest release](https://github.com/moby/moby/releases) (down to 1.6 on a best-effort basis)
# Tendermint
## 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.
@@ -28,29 +35,33 @@ For more background, see the [introduction](https://tendermint.readthedocs.io/en
To get started developing applications, see the [application developers guide](https://tendermint.readthedocs.io/en/master/getting-started.html).
# How to use this image
## 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.
A quick 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 node --proxy_app=dummy
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint node --proxy_app=kvstore
```
## mintnet-kubernetes
## Local cluster
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.
To run a 4-node network, see the `Makefile` in the root of [the repo](https://github.com/tendermint/tendermint/master/Makefile) and run:
# License
```
make build-linux
make build-docker-localnode
make localnet-start
```
View [license information](https://raw.githubusercontent.com/tendermint/tendermint/master/LICENSE) for the software contained in this image.
Note that this will build and use a different image than the ones provided here.
# User Feedback
## License
- Tendermint's license is [Apache 2.0](https://github.com/tendermint/tendermint/master/LICENSE).
## 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.
Before you start to code, we recommend discussing your plans through a [GitHub](https://github.com/tendermint/tendermint/issues) issue, especially for more ambitious contributions. This gives other contributors a chance to point you in the right direction, give you feedback on your design, and help you find out if someone else is working on the same thing.
Contributions are most welcome! See the [contributing file](https://github.com/tendermint/tendermint/blob/master/CONTRIBUTING.md) for more information.

379
Gopkg.lock generated Normal file
View File

@@ -0,0 +1,379 @@
# 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 = "86fed781132ac890ee03e906e4ecd5d6fa180c64"
[[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 = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
[[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 = "c2353362d570a7bfa228149c62842019201cfb71"
version = "v1.8.0"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b"
[[projects]]
name = "github.com/pelletier/go-toml"
packages = ["."]
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
version = "v1.2.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 = "e2704e165165ec55d062f5919b4b29494e9fa790"
[[projects]]
name = "github.com/spf13/afero"
packages = [
".",
"mem"
]
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
version = "v1.1.1"
[[projects]]
name = "github.com/spf13/cast"
packages = ["."]
revision = "8965335b8c7107321228e3e3702cab9832751bac"
version = "v1.2.0"
[[projects]]
name = "github.com/spf13/cobra"
packages = ["."]
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
version = "v0.0.3"
[[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 = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
version = "v1.2.2"
[[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 = "e2150783cd35f5b607daca48afd8c57ec54cc995"
[[projects]]
name = "github.com/tendermint/abci"
packages = [
"client",
"example/code",
"example/counter",
"example/kvstore",
"server",
"types"
]
revision = "198dccf0ddfd1bb176f87657e3286a05a6ed9540"
version = "v0.12.0"
[[projects]]
branch = "master"
name = "github.com/tendermint/ed25519"
packages = [
".",
"edwards25519",
"extra25519"
]
revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057"
[[projects]]
name = "github.com/tendermint/go-amino"
packages = ["."]
revision = "ed62928576cfcaf887209dc96142cd79cdfff389"
version = "0.9.9"
[[projects]]
name = "github.com/tendermint/go-crypto"
packages = ["."]
revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19"
version = "v0.6.2"
[[projects]]
name = "github.com/tendermint/tmlibs"
packages = [
"autofile",
"cli",
"cli/flags",
"clist",
"common",
"db",
"flowrate",
"log",
"merkle",
"test"
]
revision = "692f1d86a6e2c0efa698fd1e4541b68c74ffaf38"
version = "v0.8.4"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"curve25519",
"nacl/box",
"nacl/secretbox",
"openpgp/armor",
"openpgp/errors",
"poly1305",
"ripemd160",
"salsa20/salsa"
]
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"context",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/timeseries",
"trace"
]
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "a9e25c09b96b8870693763211309e213c6ef299d"
[[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]]
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
[[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 = "62d0626fa963b25411234da915fb3b8bfc7aefffd76824d27ac1647ca2b5d489"
solver-name = "gps-cdcl"
solver-version = 1

99
Gopkg.toml Normal file
View File

@@ -0,0 +1,99 @@
# 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.12.0"
[[constraint]]
name = "github.com/tendermint/go-crypto"
version = "~0.6.2"
[[constraint]]
name = "github.com/tendermint/go-amino"
version = "=0.9.9"
[[override]]
name = "github.com/tendermint/tmlibs"
version = "~0.8.4"
[[constraint]]
name = "google.golang.org/grpc"
version = "~1.7.3"
# this got updated and broke, so locked to an old working commit ...
[[override]]
name = "google.golang.org/genproto"
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
[prune]
go-tests = true
unused-packages = true

View File

@@ -1 +0,0 @@
The installation guide has moved to the [docs directory](docs/guides/install-from-source.md) in order to easily be rendered by the website. Please update your links accordingly.

265
Makefile Normal file → Executable file
View File

@@ -1,29 +1,135 @@
GOTOOLS = \
github.com/mitchellh/gox \
github.com/tcnksm/ghr \
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 --ldflags '-extldflags "-static"' \
--ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse HEAD`" ./cmd/tendermint
check: check_tools ensure_deps
########################################
### Build
build:
go build \
--ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse HEAD`" -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)
@@ -32,52 +138,99 @@ 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
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
list_deps:
@go list -f '{{join .Deps "\n"}}' ./... | \
grep -v /vendor/ | sort | uniq | \
xargs go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}'
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
get_vendor_deps: ensure_tools
@rm -rf vendor/
@echo "--> Running glide install"
@glide install
update_deps: tools
@echo "--> Updating dependencies"
@go get -d -u ./...
revision:
-echo `git rev-parse --verify HEAD` > $(TMHOME)/revision
-echo `git rev-parse --verify HEAD` >> $(TMHOME)/revision_history
tools:
go get -u -v $(GOTOOLS)
ensure_tools:
go get $(GOTOOLS)
########################################
### Formatting, linting, and vetting
megacheck:
@for pkg in ${PACKAGES}; do megacheck "$$pkg"; done
fmt:
@go fmt ./...
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 \
.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
metalinter_all:
@echo "--> Running linter (all)"
gometalinter.v2 --vendor --deadline=600s --enable-all --disable=lll ./...
###########################################################
### Docker image
build-docker:
cp build/tendermint DOCKER/tendermint
docker build --label=tendermint --tag="tendermint/tendermint" DOCKER
rm -rf DOCKER/tendermint
###########################################################
### Local testnet using docker
# Build linux binary on other platforms
build-linux:
GOOS=linux GOARCH=amd64 $(MAKE) build
build-docker-localnode:
cd networks/local
make
# Run a 4-node testnet locally
localnet-start: localnet-stop
@if ! [ -f build/node0/config/genesis.json ]; then docker run --rm -v $(CURDIR)/build:/tendermint:Z tendermint/localnode testnet --v 4 --o . --populate-persistent-peers --starting-ip-address 192.167.10.2 ; fi
docker-compose up
# Stop testnet
localnet-stop:
docker-compose down
###########################################################
### Remote full-nodes (sentry) using terraform and ansible
# Server management
sentry-start:
@if [ -z "$(DO_API_TOKEN)" ]; then echo "DO_API_TOKEN environment variable not set." ; false ; fi
@if ! [ -f $(HOME)/.ssh/id_rsa.pub ]; then ssh-keygen ; fi
cd networks/remote/terraform && terraform init && terraform apply -var DO_API_TOKEN="$(DO_API_TOKEN)" -var SSH_KEY_FILE="$(HOME)/.ssh/id_rsa.pub"
@if ! [ -f $(CURDIR)/build/node0/config/genesis.json ]; then docker run --rm -v $(CURDIR)/build:/tendermint:Z tendermint/localnode testnet --v 0 --n 4 --o . ; fi
cd networks/remote/ansible && ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i inventory/digital_ocean.py -l sentrynet install.yml
@echo "Next step: Add your validator setup in the genesis.json and config.tml files and run \"make sentry-config\". (Public key of validator, chain ID, peer IP and node ID.)"
# Configuration management
sentry-config:
cd networks/remote/ansible && ansible-playbook -i inventory/digital_ocean.py -l sentrynet config.yml -e BINARY=$(CURDIR)/build/tendermint -e CONFIGDIR=$(CURDIR)/build
sentry-stop:
@if [ -z "$(DO_API_TOKEN)" ]; then echo "DO_API_TOKEN environment variable not set." ; false ; fi
cd networks/remote/terraform && terraform destroy -var DO_API_TOKEN="$(DO_API_TOKEN)" -var SSH_KEY_FILE="$(HOME)/.ssh/id_rsa.pub"
# meant for the CI, inspect script & adapt accordingly
build-slate:
bash scripts/slate.sh
# 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 localnet-start localnet-stop build-docker build-docker-localnode sentry-start sentry-config sentry-stop build-slate

View File

@@ -8,7 +8,8 @@ Or [Blockchain](https://en.wikipedia.org/wiki/Blockchain_(database)) for short.
[![API Reference](
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
)](https://godoc.org/github.com/tendermint/tendermint)
[![Rocket.Chat](https://demo.rocket.chat/images/join-chat.svg)](https://cosmos.rocket.chat/)
[![Go version](https://img.shields.io/badge/go-1.9.2-blue.svg)](https://github.com/moovweb/gvm)
[![riot.im](https://img.shields.io/badge/riot.im-JOIN%20CHAT-green.svg)](https://riot.im/app/#/room/#tendermint:matrix.org)
[![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)
@@ -18,28 +19,56 @@ 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 -
and securely replicates it on many machines.
For more information, from introduction to install to application development, [Read The Docs](http://tendermint.readthedocs.io/projects/tools/en/master).
For protocol details, see [the specification](/docs/spec).
## A Note on Production Readiness
While Tendermint is being used in production in private, permissioned
environments, we are still working actively to harden and audit it in preparation
for use in public blockchains, such as the [Cosmos Network](https://cosmos.network/).
We are also still making breaking changes to the protocol and the APIs.
Thus we tag the releases as *alpha software*.
In any case, if you intend to run Tendermint in production,
please [contact us](https://riot.im/app/#/room/#tendermint:matrix.org) :)
## Security
To report a security vulnerability, see our [bug bounty
program](https://tendermint.com/security).
For examples of the kinds of bugs we're looking for, see [SECURITY.md](SECURITY.md)
## Minimum requirements
Requirement|Notes
---|---
Go version | Go1.9 or higher
## Install
To download pre-built binaries, see our [downloads page](https://tendermint.com/downloads).
See the [install instructions](/docs/install.rst)
To install from source, you should be able to:
## Quick Start
`go get -u github.com/tendermint/tendermint/cmd/tendermint`
For more details (or if it fails), [read the docs](http://tendermint.readthedocs.io/projects/tools/en/master/install.html).
- [Single node](/docs/using-tendermint.rst)
- [Local cluster using docker-compose](/networks/local)
- [Remote cluster using terraform and ansible](/docs/terraform-and-ansible.rst)
- [Join the public testnet](https://cosmos.network/testnet)
## Resources
### Tendermint Core
All resources involving the use of, building application on, or developing for, tendermint, can be found at [Read The Docs](http://tendermint.readthedocs.io/projects/tools/en/master). Additional information about some - and eventually all - of the sub-projects below, can be found at Read The Docs.
For details about the blockchain data structures and the p2p protocols, see the
the [Tendermint specification](/docs/spec).
For details on using the software, [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
@@ -54,8 +83,8 @@ All resources involving the use of, building application on, or developing for,
### Applications
* [Ethermint](http://github.com/tendermint/ethermint); Ethereum on Tendermint
* [Cosmos SDK](http://github.com/cosmos/cosmos-sdk); a cryptocurrency application framework
* [Ethermint](http://github.com/tendermint/ethermint); Ethereum on Tendermint
* [Many more](https://tendermint.readthedocs.io/en/master/ecosystem.html#abci-applications)
### More
@@ -78,7 +107,11 @@ According to SemVer, anything in the public API can change at any time before ve
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:
interfaces exposed to other processes (cli, rpc, p2p, etc.), but does not
include the in-process Go APIs.
That said, breaking changes in the following packages will be documented in the
CHANGELOG even if they don't lead to MINOR version bumps:
- types
- rpc/client

23
ROADMAP.md Normal file
View File

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

71
SECURITY.md Normal file
View File

@@ -0,0 +1,71 @@
# Security
As part of our [Coordinated Vulnerability Disclosure
Policy](https://tendermint.com/security), we operate a bug bounty.
See the policy for more details on submissions and rewards.
Here is a list of examples of the kinds of bugs we're most interested in:
## Specification
- Conceptual flaws
- Ambiguities, inconsistencies, or incorrect statements
- Mis-match between specification and implementation of any component
## Consensus
Assuming less than 1/3 of the voting power is Byzantine (malicious):
- Validation of blockchain data structures, including blocks, block parts,
votes, and so on
- Execution of blocks
- Validator set changes
- Proposer round robin
- Two nodes committing conflicting blocks for the same height (safety failure)
- A correct node signing conflicting votes
- A node halting (liveness failure)
- Syncing new and old nodes
## Networking
- Authenticated encryption (MITM, information leakage)
- Eclipse attacks
- Sybil attacks
- Long-range attacks
- Denial-of-Service
## RPC
- Write-access to anything besides sending transactions
- Denial-of-Service
- Leakage of secrets
## Denial-of-Service
Attacks may come through the P2P network or the RPC:
- Amplification attacks
- Resource abuse
- Deadlocks and race conditions
- Panics and unhandled errors
## Libraries
- Serialization (Amino)
- Reading/Writing files and databases
- Logging and monitoring
## Cryptography
- Elliptic curves for validator signatures
- Hash algorithms and Merkle trees for block validation
- Authenticated encryption for P2P connections
## Light Client
- Validation of blockchain data structures
- Correctly validating an incorrect proof
- Incorrectly validating a correct proof
- Syncing validator set changes

44
Vagrantfile vendored
View File

@@ -2,7 +2,7 @@
# 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 = 4096
@@ -11,28 +11,48 @@ Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y --no-install-recommends wget curl jq shellcheck bsdmainutils psmisc
wget -qO- https://get.docker.com/ | sh
# install base requirements
apt-get install -y --no-install-recommends wget curl jq zip \
make shellcheck bsdmainutils psmisc
apt-get install -y language-pack-en
# install docker
apt-get install -y --no-install-recommends apt-transport-https \
ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
apt-get install -y docker-ce
usermod -a -G docker vagrant
# install go
wget -q https://dl.google.com/go/go1.10.1.linux-amd64.tar.gz
tar -xvf go1.10.1.linux-amd64.tar.gz
mv go /usr/local
rm -f go1.10.1.linux-amd64.tar.gz
# cleanup
apt-get autoremove -y
curl -O https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz
tar -xvf go1.9.linux-amd64.tar.gz
rm -rf /usr/local/go
mv go /usr/local
rm -f go1.9.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
# set env variables
echo 'export GOROOT=/usr/local/go' >> /home/vagrant/.bash_profile
echo 'export GOPATH=/home/vagrant/go' >> /home/vagrant/.bash_profile
echo 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' >> /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"
"github.com/tendermint/go-amino"
"github.com/tendermint/go-crypto"
"github.com/tendermint/tendermint/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()
cdc := amino.NewCodec()
ctypes.RegisterAmino(cdc)
nodeKey := p2p.NodeKey{PrivKey: crypto.GenPrivKeyEd25519()}
status := &ctypes.ResultStatus{
NodeInfo: &p2p.NodeInfo{
PubKey: pubKey.Unwrap().(crypto.PubKeyEd25519),
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().Unwrap().(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().Unwrap().(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().Unwrap().(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

@@ -18,12 +18,16 @@ func BenchmarkFileWrite(b *testing.B) {
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

@@ -11,8 +11,8 @@ import (
)
func main() {
wsc := rpcclient.NewWSClient("127.0.0.1:46657", "/websocket")
_, err := wsc.Start()
wsc := rpcclient.NewWSClient("127.0.0.1:26657", "/websocket")
err := wsc.Start()
if err != nil {
cmn.Exit(err.Error())
}
@@ -21,7 +21,7 @@ func main() {
// Read a bunch of responses
go func() {
for {
_, ok := <-wsc.ResultsCh
_, ok := <-wsc.ResponsesCh
if !ok {
break
}

View File

@@ -1,25 +1,52 @@
package blockchain
import (
"errors"
"fmt"
"math"
"sync"
"sync/atomic"
"time"
"github.com/tendermint/tendermint/types"
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.
@@ -38,26 +65,29 @@ type BlockPool struct {
mtx sync.Mutex
// block requests
requesters map[int]*bpRequester
height int // the lowest key in requesters.
numPending int32 // number of requests pending assignment or block response
requesters map[int64]*bpRequester
height int64 // the lowest key in requesters.
// peers
peers map[string]*bpPeer
peers map[p2p.ID]*bpPeer
maxPeerHeight int64
// atomic
numPending int32 // number of requests pending assignment or block response
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 = *cmn.NewBaseService(nil, "BlockPool", bp)
return bp
@@ -69,9 +99,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() {
@@ -79,6 +107,7 @@ func (pool *BlockPool) makeRequestersRoutine() {
if !pool.IsRunning() {
break
}
_, numPending, lenRequesters := pool.GetStatus()
if numPending >= maxPendingRequests {
// sleep for a bit.
@@ -104,10 +133,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)
pool.Logger.Error("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
}
}
@@ -117,11 +150,11 @@ 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()
return pool.height, pool.numPending, len(pool.requesters)
return pool.height, atomic.LoadInt32(&pool.numPending), len(pool.requesters)
}
// TODO: relax conditions, prevent abuse.
@@ -135,16 +168,10 @@ func (pool *BlockPool) IsCaughtUp() bool {
return false
}
maxPeerHeight := 0
for _, peer := range pool.peers {
maxPeerHeight = cmn.MaxInt(maxPeerHeight, peer.height)
}
// some conditions to determine if we're caught up
receivedBlockOrTimedOut := (pool.height > 0 || time.Since(pool.startTime) > 5*time.Second)
ourChainIsLongestAmongPeers := maxPeerHeight == 0 || pool.height >= maxPeerHeight
ourChainIsLongestAmongPeers := pool.maxPeerHeight == 0 || pool.height >= pool.maxPeerHeight
isCaughtUp := receivedBlockOrTimedOut && ourChainIsLongestAmongPeers
pool.Logger.Info(cmn.Fmt("IsCaughtUp: %v", isCaughtUp), "height", pool.height, "maxPeerHeight", maxPeerHeight)
return isCaughtUp
}
@@ -180,46 +207,66 @@ func (pool *BlockPool) PopRequest() {
delete(pool.requesters, pool.height)
pool.height++
} else {
cmn.PanicSanity(cmn.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 {
cmn.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--
atomic.AddInt32(&pool.numPending, -1)
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()
@@ -231,22 +278,23 @@ func (pool *BlockPool) SetPeerHeight(peerID string, height int) {
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 {
pool.numPending++
}
go requester.redo() // pick another peer and ...
requester.redo()
}
}
delete(pool.peers, peerID)
@@ -254,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()
@@ -279,37 +327,45 @@ 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))
// request.SetLogger(pool.Logger.With("height", nextHeight))
pool.requesters[nextHeight] = request
pool.numPending++
atomic.AddInt32(&pool.numPending, 1)
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
pool.mtx.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 += cmn.Fmt("H(%v):X ", h)
} else {
@@ -324,10 +380,10 @@ func (pool *BlockPool) debug() string {
type bpPeer struct {
pool *BlockPool
id string
id p2p.ID
recvMonitor *flow.Monitor
height int
height int64
numPending int32
timeout *time.Timer
didTimeout bool
@@ -335,7 +391,7 @@ type bpPeer struct {
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,
@@ -358,9 +414,9 @@ func (peer *bpPeer) resetMonitor() {
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)
}
}
@@ -386,8 +442,9 @@ func (peer *bpPeer) onTimeout() {
peer.pool.mtx.Lock()
defer peer.pool.mtx.Unlock()
peer.pool.sendTimeout(peer.id)
peer.logger.Error("SendTimeout", "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
}
@@ -396,21 +453,21 @@ func (peer *bpPeer) onTimeout() {
type bpRequester struct {
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,
gotBlockCh: make(chan struct{}),
redoCh: make(chan struct{}),
gotBlockCh: make(chan struct{}, 1),
redoCh: make(chan struct{}, 1),
peerID: "",
block: nil,
@@ -424,8 +481,8 @@ func (bpr *bpRequester) OnStart() error {
return nil
}
// Returns true if the peer matches
func (bpr *bpRequester) setBlock(block *types.Block, peerID string) bool {
// Returns true if the peer matches and block doesn't already exist.
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 +491,10 @@ func (bpr *bpRequester) setBlock(block *types.Block, peerID string) bool {
bpr.block = block
bpr.mtx.Unlock()
bpr.gotBlockCh <- struct{}{}
select {
case bpr.gotBlockCh <- struct{}{}:
default:
}
return true
}
@@ -444,23 +504,33 @@ 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
}
// This is called from the requestRoutine, upon redo().
func (bpr *bpRequester) reset() {
bpr.mtx.Lock()
defer bpr.mtx.Unlock()
if bpr.block != nil {
atomic.AddInt32(&bpr.pool.numPending, 1)
}
bpr.peerID = ""
bpr.block = nil
bpr.mtx.Unlock()
}
// Tells bpRequester to pick another peer and try again.
// NOTE: blocking
// NOTE: Nonblocking, and does nothing if another redo
// was already requested.
func (bpr *bpRequester) redo() {
bpr.redoCh <- struct{}{}
select {
case bpr.redoCh <- struct{}{}:
default:
}
}
// Responsible for making more requests as necessary
@@ -469,7 +539,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() {
@@ -489,26 +559,21 @@ OUTER_LOOP:
// Send request and wait.
bpr.pool.sendRequest(bpr.height, peer.id)
select {
case <-bpr.pool.Quit:
bpr.Stop()
return
case <-bpr.Quit:
return
case <-bpr.redoCh:
bpr.reset()
continue OUTER_LOOP // When peer is removed
case <-bpr.gotBlockCh:
// We got the block, now see if it's good.
WAIT_LOOP:
for {
select {
case <-bpr.pool.Quit:
case <-bpr.pool.Quit():
bpr.Stop()
return
case <-bpr.Quit:
case <-bpr.Quit():
return
case <-bpr.redoCh:
bpr.reset()
continue OUTER_LOOP
case <-bpr.gotBlockCh:
// We got a block!
// Continue the for-loop and wait til Quit.
continue WAIT_LOOP
}
}
}
@@ -517,6 +582,6 @@ OUTER_LOOP:
//-------------------------------------
type BlockRequest struct {
Height int
PeerID string
Height int64
PeerID p2p.ID
}

View File

@@ -5,38 +5,45 @@ import (
"testing"
"time"
"github.com/tendermint/tendermint/types"
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 := cmn.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)
errorsCh := make(chan peerError, 1000)
requestsCh := make(chan BlockRequest, 1000)
pool := NewBlockPool(start, requestsCh, errorsCh)
pool.SetLogger(log.TestingLogger())
pool.Start()
err := pool.Start()
if err != nil {
t.Error(err)
}
defer pool.Stop()
// Introduce each peer.
@@ -64,8 +71,8 @@ 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:
t.Logf("Pulled new BlockRequest %v", request)
if request.Height == 300 {
@@ -82,13 +89,16 @@ func TestBasic(t *testing.T) {
}
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)
errorsCh := make(chan peerError, 1000)
requestsCh := make(chan BlockRequest, 1000)
pool := NewBlockPool(start, requestsCh, errorsCh)
pool.SetLogger(log.TestingLogger())
pool.Start()
err := pool.Start()
if err != nil {
t.Error(err)
}
defer pool.Stop()
for _, peer := range peers {
@@ -119,12 +129,13 @@ func TestTimeout(t *testing.T) {
// Pull from channels
counter := 0
timedOut := map[string]struct{}{}
timedOut := map[p2p.ID]struct{}{}
for {
select {
case peerID := <-timeoutsCh:
t.Logf("Peer %v timeouted", 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!

View File

@@ -1,25 +1,23 @@
package blockchain
import (
"bytes"
"errors"
"fmt"
"reflect"
"time"
wire "github.com/tendermint/go-wire"
"github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/proxy"
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
trySyncIntervalMS = 100
trySyncIntervalMS = 50
// stop syncing when last block's time is
// within this much of the system time.
// stopSyncingDurationMinutes = 10
@@ -28,62 +26,91 @@ const (
statusUpdateIntervalSeconds = 10
// check if we should switch to consensus reactor
switchToConsensusIntervalSeconds = 1
// 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
state *sm.State
proxyAppConn proxy.AppConnConsensus // same as consensus.proxyAppConn
store *BlockStore
pool *BlockPool
fastSync bool
requestsCh chan BlockRequest
timeoutsCh chan string
// 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(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{
state: state,
proxyAppConn: proxyAppConn,
initialState: state,
blockExec: blockExec,
store: store,
pool: pool,
fastSync: fastSync,
requestsCh: requestsCh,
timeoutsCh: timeoutsCh,
errorsCh: errorsCh,
}
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
}
@@ -92,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()
@@ -101,55 +128,61 @@ 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()}}) {
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())
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) {
func (bcR *BlockchainReactor) respondToPeer(msg *bcBlockRequestMessage,
src p2p.Peer) (queued bool) {
block := bcR.store.LoadBlock(msg.Height)
if block != nil {
msg := &bcBlockResponseMessage{Block: block}
return src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg})
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)
return src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{
&bcNoBlockResponseMessage{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, bcR.maxMsgSize())
msg, err := DecodeMessage(msgBytes)
if err != nil {
bcR.Logger.Error("Error decoding message", "err", err)
bcR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
bcR.Switch.StopPeerForError(src, err)
return
}
bcR.Logger.Debug("Receive", "src", src, "chID", chID, "msg", msg)
// TODO: improve logic to satisfy megacheck
switch msg := msg.(type) {
case *bcBlockRequestMessage:
if queued := bcR.respondToPeer(msg, src); !queued {
@@ -157,27 +190,22 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
}
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:
bcR.Logger.Error(cmn.Fmt("Unknown message type %v", reflect.TypeOf(msg)))
}
}
// maxMsgSize returns the maximum allowable size of a
// message on the blockchain reactor.
func (bcR *BlockchainReactor) maxMsgSize() int {
return bcR.state.Params().BlockSizeParams.MaxBytes + 2
}
// Handle messages from the poolReactor telling the reactor what to do.
// NOTE: Don't sleep in the FOR_LOOP or otherwise slow it down!
// (Except for the SYNC_LOOP, which is the primary purpose and must be synchronous.)
@@ -187,41 +215,48 @@ 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:
// ask for status updates
go bcR.BroadcastStatusRequest()
go bcR.BroadcastStatusRequest() // nolint: errcheck
case <-switchToConsensusTicker.C:
height, numPending, _ := bcR.pool.GetStatus()
height, numPending, lenRequesters := bcR.pool.GetStatus()
outbound, inbound, _ := bcR.Switch.NumPeers()
bcR.Logger.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() {
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
}
@@ -236,36 +271,50 @@ FOR_LOOP:
// We need both to sync the first block.
break SYNC_LOOP
}
firstParts := first.MakePartSet(bcR.state.Params().BlockPartSizeBytes)
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 {
bcR.Logger.Error("Error in validation", "err", err)
bcR.pool.RedoRequest(first.Height)
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
}
}
@@ -273,47 +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)
msgTypeNoBlockResponse = byte(0x12)
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{&bcNoBlockResponseMessage{}, msgTypeNoBlockResponse},
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, maxSize int) (msgType byte, msg BlockchainMessage, err error) {
msgType = bz[0]
n := int(0)
r := bytes.NewReader(bz)
msg = wire.ReadBinary(struct{ BlockchainMessage }{}, r, maxSize, &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
}
@@ -321,7 +359,7 @@ func DecodeMessage(bz []byte, maxSize int) (msgType byte, msg BlockchainMessage,
//-------------------------------------
type bcBlockRequestMessage struct {
Height int
Height int64
}
func (m *bcBlockRequestMessage) String() string {
@@ -329,7 +367,7 @@ func (m *bcBlockRequestMessage) String() string {
}
type bcNoBlockResponseMessage struct {
Height int
Height int64
}
func (brm *bcNoBlockResponseMessage) String() string {
@@ -338,7 +376,6 @@ func (brm *bcNoBlockResponseMessage) String() string {
//-------------------------------------
// NOTE: keep up-to-date with maxBlockchainResponseSize
type bcBlockResponseMessage struct {
Block *types.Block
}
@@ -350,7 +387,7 @@ func (m *bcBlockResponseMessage) String() string {
//-------------------------------------
type bcStatusRequestMessage struct {
Height int
Height int64
}
func (m *bcStatusRequestMessage) String() string {
@@ -360,7 +397,7 @@ func (m *bcStatusRequestMessage) String() string {
//-------------------------------------
type bcStatusResponseMessage struct {
Height int
Height int64
}
func (m *bcStatusResponseMessage) String() string {

View File

@@ -1,71 +1,75 @@
package blockchain
import (
"bytes"
"net"
"testing"
wire "github.com/tendermint/go-wire"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/db"
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 newBlockchainReactor(logger log.Logger, maxBlockHeight int) *BlockchainReactor {
config := cfg.ResetTestRoot("node_node_test")
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
}
blockStoreDB := db.NewDB("blockstore", config.DBBackend, config.DBDir())
blockStore := NewBlockStore(blockStoreDB)
stateLogger := logger.With("module", "state")
// Get State
stateDB := db.NewDB("state", config.DBBackend, config.DBDir())
state, _ := sm.GetState(stateDB, config.GenesisFile())
state.SetLogger(stateLogger)
state.Save()
func newBlockchainReactor(logger log.Logger, maxBlockHeight int64) *BlockchainReactor {
state, blockStore := makeStateAndBlockStore(logger)
// Make the blockchainReactor itself
fastSync := true
bcReactor := NewBlockchainReactor(state.Copy(), nil, blockStore, fastSync)
var nilApp proxy.AppConnConsensus
blockExec := sm.NewBlockExecutor(dbm.NewMemDB(), log.TestingLogger(), nilApp,
sm.MockMempool{}, sm.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())
bcReactor.SetLogger(logger.With("module", "blockchain"))
// Lastly: let's add some blocks in
for blockHeight := 1; blockHeight <= maxBlockHeight; blockHeight++ {
for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ {
firstBlock := makeBlock(blockHeight, state)
secondBlock := makeBlock(blockHeight+1, state)
firstParts := firstBlock.MakePartSet(state.Params().BlockGossipParams.BlockPartSizeBytes)
firstParts := firstBlock.MakePartSet(state.ConsensusParams.BlockGossip.BlockPartSizeBytes)
blockStore.SaveBlock(firstBlock, firstParts, secondBlock.LastCommit)
}
return bcReactor
}
func TestNoBlockMessageResponse(t *testing.T) {
logBuf := new(bytes.Buffer)
logger := log.NewTMLogger(logBuf)
maxBlockHeight := 20
func TestNoBlockResponse(t *testing.T) {
maxBlockHeight := int64(20)
bcr := newBlockchainReactor(logger, maxBlockHeight)
go bcr.OnStart()
bcr := newBlockchainReactor(log.TestingLogger(), maxBlockHeight)
bcr.Start()
defer bcr.Stop()
// Add some peers in
peer := newbcrTestPeer(cmn.RandStr(12))
peer := newbcrTestPeer(p2p.ID(cmn.RandStr(12)))
bcr.AddPeer(peer)
chID := byte(0x01)
tests := []struct {
height int
height int64
existent bool
}{
{maxBlockHeight + 2, false},
@@ -74,12 +78,13 @@ func TestNoBlockMessageResponse(t *testing.T) {
{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 := wire.BinaryBytes(struct{ BlockchainMessage }{reqBlockMsg})
reqBlockBytes := cdc.MustMarshalBinaryBare(reqBlockMsg)
bcr.Receive(chID, peer, reqBlockBytes)
value := peer.lastValue()
msg := value.(struct{ BlockchainMessage }).BlockchainMessage
msg := peer.lastBlockchainMessage()
if tt.existent {
if blockMsg, ok := msg.(*bcBlockResponseMessage); !ok {
@@ -97,62 +102,107 @@ func TestNoBlockMessageResponse(t *testing.T) {
}
}
/*
// NOTE: This is too hard to test without
// an easy way to add test peer to switch
// or without significant refactoring of the module.
// Alternatively we could actually dial a TCP conn but
// that seems extreme.
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(blockNumber int) (txs []types.Tx) {
func makeTxs(height int64) (txs []types.Tx) {
for i := 0; i < 10; i++ {
txs = append(txs, types.Tx([]byte{byte(blockNumber), byte(i)}))
txs = append(txs, types.Tx([]byte{byte(height), byte(i)}))
}
return txs
}
func makeBlock(blockNumber int, state *sm.State) *types.Block {
prevHash := state.LastBlockID.Hash
prevParts := types.PartSetHeader{}
valHash := state.Validators.Hash()
prevBlockID := types.BlockID{prevHash, prevParts}
block, _ := types.MakeBlock(blockNumber, "test_chain", makeTxs(blockNumber),
new(types.Commit), prevBlockID, valHash, state.AppHash, state.Params().BlockGossipParams.BlockPartSizeBytes)
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.Service
key string
ch chan interface{}
cmn.BaseService
id p2p.ID
ch chan interface{}
}
var _ p2p.Peer = (*bcrTestPeer)(nil)
func newbcrTestPeer(key string) *bcrTestPeer {
return &bcrTestPeer{
Service: cmn.NewBaseService(nil, "bcrTestPeer", nil),
key: key,
ch: make(chan interface{}, 2),
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) lastValue() interface{} { return <-tp.ch }
func (tp *bcrTestPeer) lastBlockchainMessage() interface{} { return <-tp.ch }
func (tp *bcrTestPeer) TrySend(chID byte, value interface{}) bool {
if _, ok := value.(struct{ BlockchainMessage }).BlockchainMessage.(*bcStatusResponseMessage); ok {
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 <- value
tp.ch <- msg
}
return true
}
func (tp *bcrTestPeer) Send(chID byte, data interface{}) bool { return tp.TrySend(chID, data) }
func (tp *bcrTestPeer) NodeInfo() *p2p.NodeInfo { return nil }
func (tp *bcrTestPeer) Status() p2p.ConnectionStatus { return p2p.ConnectionStatus{} }
func (tp *bcrTestPeer) Key() string { return tp.key }
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{}) {}
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{}) {}
func (tp *bcrTestPeer) RemoteIP() net.IP { return []byte{127, 0, 0, 1} }

View File

@@ -1,20 +1,17 @@
package blockchain
import (
"bytes"
"encoding/json"
"fmt"
"io"
"sync"
. "github.com/tendermint/tmlibs/common"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/go-wire"
"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)
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 (
"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"
"github.com/tendermint/tendermint/privval"
)
func main() {
var (
addr = flag.String("addr", ":26659", "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,
)
pv := privval.LoadFilePV(*privValPath)
rs := privval.NewRemoteSigner(
logger,
*chainID,
*addr,
pv,
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

@@ -1,12 +1,11 @@
package commands
import (
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/privval"
)
// GenValidatorCmd allows the generation of a keypair for a
@@ -18,8 +17,11 @@ var GenValidatorCmd = &cobra.Command{
}
func genValidator(cmd *cobra.Command, args []string) {
privValidator := types.GenPrivValidatorFS("")
privValidatorJSONBytes, _ := json.MarshalIndent(privValidator, "", "\t")
pv := privval.GenFilePV("")
jsbz, err := cdc.MarshalJSON(pv)
if err != nil {
panic(err)
}
fmt.Printf(`%v
`, string(privValidatorJSONBytes))
`, string(jsbz))
}

View File

@@ -1,10 +1,13 @@
package commands
import (
"os"
"time"
"github.com/spf13/cobra"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
@@ -13,31 +16,55 @@ import (
var InitFilesCmd = &cobra.Command{
Use: "init",
Short: "Initialize Tendermint",
Run: initFiles,
RunE: initFiles,
}
func initFiles(cmd *cobra.Command, args []string) {
func initFiles(cmd *cobra.Command, args []string) error {
return initFilesWithConfig(config)
}
func initFilesWithConfig(config *cfg.Config) error {
// private validator
privValFile := config.PrivValidatorFile()
if _, err := os.Stat(privValFile); os.IsNotExist(err) {
privValidator := types.GenPrivValidatorFS(privValFile)
privValidator.Save()
genFile := config.GenesisFile()
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.GetPubKey(),
Power: 10,
}}
genDoc.SaveAs(genFile)
}
logger.Info("Initialized tendermint", "genesis", config.GenesisFile(), "priv_validator", config.PrivValidatorFile())
var pv *privval.FilePV
if cmn.FileExists(privValFile) {
pv = privval.LoadFilePV(privValFile)
logger.Info("Found private validator", "path", privValFile)
} else {
logger.Info("Already initialized", "priv_validator", config.PrivValidatorFile())
pv = privval.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)),
GenesisTime: time.Now(),
}
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:26657", "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,7 +1,6 @@
package commands
import (
"encoding/json"
"fmt"
"github.com/spf13/cobra"
@@ -19,10 +18,10 @@ var ProbeUpnpCmd = &cobra.Command{
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 {
return err
}

View File

@@ -5,7 +5,7 @@ import (
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tmlibs/log"
)
@@ -13,46 +13,57 @@ import (
// instance.
var ResetAllCmd = &cobra.Command{
Use: "unsafe_reset_all",
Short: "(unsafe) Remove all the data and WAL, reset this node's validator",
Short: "(unsafe) Remove all the data and WAL, reset this node's validator to genesis state",
Run: resetAll,
}
// ResetPrivValidatorCmd resets the private validator files.
var ResetPrivValidatorCmd = &cobra.Command{
Use: "unsafe_reset_priv_validator",
Short: "(unsafe) Reset this node's validator",
Short: "(unsafe) Reset this node's validator to genesis state",
Run: resetPrivValidator,
}
// ResetAll removes the privValidator files.
// Exported so other CLI tools can use it
func ResetAll(dbDir, privValFile string, logger log.Logger) {
resetPrivValidatorFS(privValFile, logger)
os.RemoveAll(dbDir)
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.DBDir(), config.PrivValidatorFile(), logger)
ResetAll(config.DBDir(), config.P2P.AddrBookFile(), config.PrivValidatorFile(), logger)
}
// XXX: this is totally unsafe.
// it's only suitable for testnets.
func resetPrivValidator(cmd *cobra.Command, args []string) {
resetPrivValidatorFS(config.PrivValidatorFile(), logger)
resetFilePV(config.PrivValidatorFile(), logger)
}
func resetPrivValidatorFS(privValFile string, logger log.Logger) {
// Get PrivValidator
if _, err := os.Stat(privValFile); err == nil {
privValidator := types.LoadPrivValidatorFS(privValFile)
privValidator.Reset()
logger.Info("Reset PrivValidator", "file", privValFile)
// ResetAll removes the privValidator and address book files plus all data.
// Exported so other CLI tools can use it.
func ResetAll(dbDir, addrBookFile, privValFile string, logger log.Logger) {
resetFilePV(privValFile, logger)
removeAddrBook(addrBookFile, logger)
if err := os.RemoveAll(dbDir); err == nil {
logger.Info("Removed all blockchain history", "dir", dbDir)
} else {
privValidator := types.GenPrivValidatorFS(privValFile)
privValidator.Save()
logger.Info("Generated PrivValidator", "file", privValFile)
logger.Error("Error removing all blockchain history", "dir", dbDir, "err", err)
}
}
func resetFilePV(privValFile string, logger log.Logger) {
if _, err := os.Stat(privValFile); err == nil {
pv := privval.LoadFilePV(privValFile)
pv.Reset()
logger.Info("Reset private validator file to genesis state", "file", privValFile)
} else {
pv := privval.GenFilePV(privValFile)
pv.Save()
logger.Info("Generated private validator file", "file", privValFile)
}
}
func removeAddrBook(addrBookFile string, logger log.Logger) {
if err := os.Remove(addrBookFile); err == nil {
logger.Info("Removed existing address book", "file", addrBookFile)
} else if !os.IsNotExist(err) {
logger.Info("Error removing address book", "file", addrBookFile, "err", err)
}
}

View File

@@ -14,11 +14,15 @@ import (
var (
config = cfg.DefaultConfig()
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "main")
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
)
func init() {
RootCmd.PersistentFlags().String("log_level", config.LogLevel, "Log level")
registerFlagsRootCmd(RootCmd)
}
func registerFlagsRootCmd(cmd *cobra.Command) {
cmd.PersistentFlags().String("log_level", config.LogLevel, "Log level")
}
// ParseConfig retrieves the default environment configuration,
@@ -53,6 +57,7 @@ var RootCmd = &cobra.Command{
if viper.GetBool(cli.TraceFlag) {
logger = log.NewTracingLogger(logger)
}
logger = logger.With("module", "main")
return nil
},
}

View File

@@ -1,7 +1,10 @@
package commands
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"testing"
@@ -12,6 +15,7 @@ import (
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tmlibs/cli"
cmn "github.com/tendermint/tmlibs/common"
)
var (
@@ -22,84 +26,151 @@ const (
rootName = "root"
)
// isolate provides a clean setup and returns a copy of RootCmd you can
// modify in the test cases.
// NOTE: it unsets all TM* env variables.
func isolate(cmds ...*cobra.Command) cli.Executable {
os.Unsetenv("TMHOME")
os.Unsetenv("TM_HOME")
os.Unsetenv("TMROOT")
os.Unsetenv("TM_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()
r := &cobra.Command{
Use: rootName,
PersistentPreRunE: RootCmd.PersistentPreRunE,
}
r.AddCommand(cmds...)
wr := cli.PrepareBaseCmd(r, "TM", defaultRoot)
return wr
}
func TestRootConfig(t *testing.T) {
assert, require := assert.New(t), require.New(t)
// we pre-create a config file we can refer to in the rest of
// the test cases.
cvals := map[string]string{
"moniker": "monkey",
"fast_sync": "false",
// prepare new rootCmd
func testRootCmd() *cobra.Command {
rootCmd := &cobra.Command{
Use: RootCmd.Use,
PersistentPreRunE: RootCmd.PersistentPreRunE,
Run: func(cmd *cobra.Command, args []string) {},
}
// proper types of the above settings
cfast := false
conf, err := cli.WriteDemoConfig(cvals)
require.Nil(err)
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()
dmax := defaults.P2P.MaxNumPeers
defaultLogLvl := defaults.LogLevel
cases := []struct {
args []string
env map[string]string
root string
moniker string
fastSync bool
maxPeer int
logLevel string
}{
{nil, nil, defaultRoot, defaults.Moniker, defaults.FastSync, dmax},
// try multiple ways of setting root (two flags, cli vs. env)
{[]string{"--home", conf}, nil, conf, cvals["moniker"], cfast, dmax},
{nil, map[string]string{"TMROOT": conf}, conf, cvals["moniker"], cfast, dmax},
// check setting p2p subflags two different ways
{[]string{"--p2p.max_num_peers", "420"}, nil, defaultRoot, defaults.Moniker, defaults.FastSync, 420},
{nil, map[string]string{"TM_P2P_MAX_NUM_PEERS": "17"}, defaultRoot, defaults.Moniker, defaults.FastSync, 17},
// try to set env that have no flags attached...
{[]string{"--home", conf}, map[string]string{"TM_MONIKER": "funny"}, conf, "funny", cfast, dmax},
{[]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 idx, tc := range cases {
i := strconv.Itoa(idx)
// test command that does nothing, except trigger unmarshalling in root
noop := &cobra.Command{
Use: "noop",
RunE: func(cmd *cobra.Command, args []string) error {
return nil
},
}
noop.Flags().Int("p2p.max_num_peers", defaults.P2P.MaxNumPeers, "")
cmd := isolate(noop)
for i, tc := range cases {
idxString := strconv.Itoa(i)
args := append([]string{rootName, noop.Use}, tc.args...)
err := cli.RunWithArgs(cmd, args, tc.env)
require.Nil(err, i)
assert.Equal(tc.root, config.RootDir, i)
assert.Equal(tc.root, config.P2P.RootDir, i)
assert.Equal(tc.root, config.Consensus.RootDir, i)
assert.Equal(tc.root, config.Mempool.RootDir, i)
assert.Equal(tc.moniker, config.Moniker, i)
assert.Equal(tc.fastSync, config.FastSync, i)
assert.Equal(tc.maxPeer, config.P2P.MaxNumPeers, 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

@@ -14,11 +14,14 @@ 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 'dummy' for local testing.")
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
@@ -28,16 +31,19 @@ func AddNodeFlags(cmd *cobra.Command) {
// 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 host:port seed nodes")
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 Peer-Exchange (dev feature)")
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")
}
// 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.
// 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",
@@ -49,11 +55,10 @@ func NewRunNodeCmd(nodeProvider nm.NodeProvider) *cobra.Command {
return fmt.Errorf("Failed to create node: %v", err)
}
if _, err := n.Start(); err != nil {
if err := n.Start(); err != nil {
return fmt.Errorf("Failed to start node: %v", err)
} else {
logger.Info("Started node", "nodeInfo", n.Switch().NodeInfo())
}
logger.Info("Started node", "nodeInfo", n.Switch().NodeInfo())
// Trap signal, run forever.
n.RunForever()

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,8 +5,7 @@ import (
"github.com/spf13/cobra"
"github.com/tendermint/go-wire/data"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/privval"
)
// ShowValidatorCmd adds capabilities for showing the validator info.
@@ -17,7 +16,7 @@ var ShowValidatorCmd = &cobra.Command{
}
func showValidator(cmd *cobra.Command, args []string) {
privValidator := types.LoadOrGenPrivValidatorFS(config.PrivValidatorFile())
pubKeyJSONBytes, _ := data.ToJSON(privValidator.PubKey)
privValidator := privval.LoadOrGenFilePV(config.PrivValidatorFile())
pubKeyJSONBytes, _ := cdc.MarshalJSON(privValidator.GetPubKey())
fmt.Println(string(pubKeyJSONBytes))
}

View File

@@ -2,57 +2,114 @@ package commands
import (
"fmt"
"path"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/spf13/cobra"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
//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, ...)")
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:26656, ID1@node1:26656, ...)")
TestnetFilesCmd.Flags().StringVar(&startingIPAddress, "starting-ip-address", "",
"Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:26656, ID1@192.168.0.2:26656, ...)")
TestnetFilesCmd.Flags().IntVar(&p2pPort, "p2p-port", 26656,
"P2P Port")
}
// TestnetFilesCmd allows initialisation of files for a
// Tendermint testnet.
// TestnetFilesCmd allows initialisation of files for a Tendermint testnet.
var TestnetFilesCmd = &cobra.Command{
Use: "testnet",
Short: "Initialize files for a Tendermint testnet",
Run: testnetFiles,
Long: `testnet will create "v" + "n" number of directories and populate each with
necessary files (private validator, genesis, config, etc.).
Note, strict routability for addresses is turned off in the config file.
Optionally, it will fill in persistent_peers list in config file using either hostnames or IPs.
Example:
tendermint testnet --v 4 --o ./output --populate-persistent-peers --starting-ip-address 192.168.10.2
`,
RunE: testnetFiles,
}
func testnetFiles(cmd *cobra.Command, args []string) {
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.LoadPrivValidatorFS(privValFile)
initFilesWithConfig(config)
pvFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidator)
pv := privval.LoadFilePV(pvFile)
genVals[i] = types.GenesisValidator{
PubKey: privVal.GetPubKey(),
PubKey: pv.GetPubKey(),
Power: 1,
Name: mach,
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,32 +118,66 @@ 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.GenPrivValidatorFS(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
config.P2P.AddrBookStrict = false
// overwrite default config
cfg.WriteConfigFile(filepath.Join(nodeDir, "config", "config.toml"), config)
}
return nil
}

View File

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

View File

@@ -2,10 +2,12 @@ package main
import (
"os"
"path/filepath"
"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"
)
@@ -15,12 +17,15 @@ func main() {
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:
@@ -36,6 +41,8 @@ func main() {
// Create & start node
rootCmd.AddCommand(cmd.NewRunNodeCmd(nodeFunc))
cmd := cli.PrepareBaseCmd(rootCmd, "TM", os.ExpandEnv("$HOME/.tendermint"))
cmd.Execute()
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"

View File

@@ -2,10 +2,43 @@ package config
import (
"fmt"
"os"
"path/filepath"
"time"
)
const (
// FuzzModeDrop is a mode in which we randomly drop reads/writes, connections or sleep
FuzzModeDrop = iota
// FuzzModeDelay is a mode in which we randomly sleep
FuzzModeDelay
)
// 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
@@ -16,6 +49,7 @@ type Config struct {
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
@@ -26,6 +60,7 @@ func DefaultConfig() *Config {
P2P: DefaultP2PConfig(),
Mempool: DefaultMempoolConfig(),
Consensus: DefaultConsensusConfig(),
TxIndex: DefaultTxIndexConfig(),
}
}
@@ -35,8 +70,9 @@ func TestConfig() *Config {
BaseConfig: TestBaseConfig(),
RPC: TestRPCConfig(),
P2P: TestP2PConfig(),
Mempool: DefaultMempoolConfig(),
Mempool: TestMempoolConfig(),
Consensus: TestConsensusConfig(),
TxIndex: TestTxIndexConfig(),
}
}
@@ -55,22 +91,30 @@ func (cfg *Config) SetRoot(root string) *Config {
// 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"`
// The ID of the chain to join (should be signed with every transaction and vote)
ChainID string `mapstructure:"chain_id"`
// A JSON file containing the initial validator set and other meta data
// Path to the JSON file containing the initial validator set and other meta data
Genesis string `mapstructure:"genesis_file"`
// A JSON file containing the private key to use as a validator in the consensus protocol
// 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"`
@@ -93,9 +137,6 @@ type BaseConfig struct {
// so the app can decide if we should keep the connection or not
FilterPeers bool `mapstructure:"filter_peers"` // false
// What indexer to use for transactions
TxIndex string `mapstructure:"tx_index"`
// Database backend: leveldb | memdb
DBBackend string `mapstructure:"db_backend"`
@@ -106,16 +147,16 @@ type BaseConfig struct {
// DefaultBaseConfig returns a default base configuration for a Tendermint node
func DefaultBaseConfig() BaseConfig {
return BaseConfig{
Genesis: "genesis.json",
PrivValidator: "priv_validator.json",
Moniker: "anonymous",
ProxyApp: "tcp://127.0.0.1:46658",
Genesis: defaultGenesisJSONPath,
PrivValidator: defaultPrivValPath,
NodeKey: defaultNodeKeyPath,
Moniker: defaultMoniker,
ProxyApp: "tcp://127.0.0.1:26658",
ABCI: "socket",
LogLevel: DefaultPackageLogLevels(),
ProfListenAddress: "",
FastSync: true,
FilterPeers: false,
TxIndex: "kv",
DBBackend: "leveldb",
DBPath: "data",
}
@@ -123,27 +164,36 @@ func DefaultBaseConfig() BaseConfig {
// TestBaseConfig returns a base configuration for testing a Tendermint node
func TestBaseConfig() BaseConfig {
conf := DefaultBaseConfig()
conf.ChainID = "tendermint_test"
conf.ProxyApp = "dummy"
conf.FastSync = false
conf.DBBackend = "memdb"
return conf
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 (b BaseConfig) GenesisFile() string {
return rootify(b.Genesis, b.RootDir)
func (cfg BaseConfig) GenesisFile() string {
return rootify(cfg.Genesis, cfg.RootDir)
}
// PrivValidatorFile returns the full path to the priv_validator.json file
func (b BaseConfig) PrivValidatorFile() string {
return rootify(b.PrivValidator, b.RootDir)
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 (b BaseConfig) DBDir() string {
return rootify(b.DBPath, b.RootDir)
func (cfg BaseConfig) DBDir() string {
return rootify(cfg.DBPath, cfg.RootDir)
}
// DefaultLogLevel returns a default log level of "error"
@@ -151,9 +201,10 @@ func DefaultLogLevel() string {
return "error"
}
// DefaultPackageLogLevels returns a default log level setting so all packages log at "error", while the `state` package logs at "info"
// 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("state:info,*:%s", DefaultLogLevel())
return fmt.Sprintf("main:info,state:info,*:%s", DefaultLogLevel())
}
//-----------------------------------------------------------------------------
@@ -170,14 +221,14 @@ type RPCConfig struct {
// NOTE: This server only supports /broadcast_tx_commit
GRPCListenAddress string `mapstructure:"grpc_laddr"`
// Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
// 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",
ListenAddress: "tcp://0.0.0.0:26657",
GRPCListenAddress: "",
Unsafe: false,
}
@@ -185,11 +236,11 @@ func DefaultRPCConfig() *RPCConfig {
// TestRPCConfig returns a configuration for testing the RPC server
func TestRPCConfig() *RPCConfig {
conf := DefaultRPCConfig()
conf.ListenAddress = "tcp://0.0.0.0:36657"
conf.GRPCListenAddress = "tcp://0.0.0.0:36658"
conf.Unsafe = true
return conf
cfg := DefaultRPCConfig()
cfg.ListenAddress = "tcp://0.0.0.0:36657"
cfg.GRPCListenAddress = "tcp://0.0.0.0:36658"
cfg.Unsafe = true
return cfg
}
//-----------------------------------------------------------------------------
@@ -203,8 +254,13 @@ type P2PConfig struct {
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"`
@@ -214,9 +270,6 @@ type P2PConfig struct {
// Set true for strict address routability rules
AddrBookStrict bool `mapstructure:"addr_book_strict"`
// Set true to enable the peer-exchange reactor
PexReactor bool `mapstructure:"pex"`
// Maximum number of peers to connect to
MaxNumPeers int `mapstructure:"max_num_peers"`
@@ -224,40 +277,97 @@ type P2PConfig struct {
FlushThrottleTimeout int `mapstructure:"flush_throttle_timeout"`
// Maximum size of a message packet payload, in bytes
MaxMsgPacketPayloadSize int `mapstructure:"max_msg_packet_payload_size"`
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"`
// Comma separated list of peer IDs to keep private (will not be gossiped to
// other peers)
PrivatePeerIDs string `mapstructure:"private_peer_ids"`
// Toggle to disable guard against peers connecting from the same ip.
AllowDuplicateIP bool `mapstructure:"allow_duplicate_ip"`
// Peer connection configuration.
HandshakeTimeout time.Duration `mapstructure:"handshake_timeout"`
DialTimeout time.Duration `mapstructure:"dial_timeout"`
// Testing params.
// Force dial to fail
TestDialFail bool `mapstructure:"test_dial_fail"`
// FUzz connection
TestFuzz bool `mapstructure:"test_fuzz"`
TestFuzzConfig *FuzzConnConfig `mapstructure:"test_fuzz_config"`
}
// DefaultP2PConfig returns a default configuration for the peer-to-peer layer
func DefaultP2PConfig() *P2PConfig {
return &P2PConfig{
ListenAddress: "tcp://0.0.0.0:46656",
AddrBook: "addrbook.json",
ListenAddress: "tcp://0.0.0.0:26656",
AddrBook: defaultAddrBookPath,
AddrBookStrict: true,
MaxNumPeers: 50,
FlushThrottleTimeout: 100,
MaxMsgPacketPayloadSize: 1024, // 1 kB
MaxPacketMsgPayloadSize: 1024, // 1 kB
SendRate: 512000, // 500 kB/s
RecvRate: 512000, // 500 kB/s
PexReactor: true,
SeedMode: false,
AllowDuplicateIP: true, // so non-breaking yet
HandshakeTimeout: 20 * time.Second,
DialTimeout: 3 * time.Second,
TestDialFail: false,
TestFuzz: false,
TestFuzzConfig: DefaultFuzzConnConfig(),
}
}
// TestP2PConfig returns a configuration for testing the peer-to-peer layer
func TestP2PConfig() *P2PConfig {
conf := DefaultP2PConfig()
conf.ListenAddress = "tcp://0.0.0.0:36656"
conf.SkipUPNP = true
return conf
cfg := DefaultP2PConfig()
cfg.ListenAddress = "tcp://0.0.0.0:36656"
cfg.SkipUPNP = true
cfg.FlushThrottleTimeout = 10
cfg.AllowDuplicateIP = true
return cfg
}
// AddrBookFile returns the full path to the address bool
func (p *P2PConfig) AddrBookFile() string {
return rootify(p.AddrBook, p.RootDir)
// AddrBookFile returns the full path to the address book
func (cfg *P2PConfig) AddrBookFile() string {
return rootify(cfg.AddrBook, cfg.RootDir)
}
// FuzzConnConfig is a FuzzedConnection configuration.
type FuzzConnConfig struct {
Mode int
MaxDelay time.Duration
ProbDropRW float64
ProbDropConn float64
ProbSleep float64
}
// DefaultFuzzConnConfig returns the default config.
func DefaultFuzzConnConfig() *FuzzConnConfig {
return &FuzzConnConfig{
Mode: FuzzModeDrop,
MaxDelay: 3 * time.Second,
ProbDropRW: 0.2,
ProbDropConn: 0.00,
ProbSleep: 0.00,
}
}
//-----------------------------------------------------------------------------
@@ -270,6 +380,8 @@ type MempoolConfig struct {
RecheckEmpty bool `mapstructure:"recheck_empty"`
Broadcast bool `mapstructure:"broadcast"`
WalPath string `mapstructure:"wal_dir"`
Size int `mapstructure:"size"`
CacheSize int `mapstructure:"cache_size"`
}
// DefaultMempoolConfig returns a default configuration for the Tendermint mempool
@@ -278,13 +390,22 @@ func DefaultMempoolConfig() *MempoolConfig {
Recheck: true,
RecheckEmpty: true,
Broadcast: true,
WalPath: "data/mempool.wal",
WalPath: filepath.Join(defaultDataDir, "mempool.wal"),
Size: 100000,
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 (m *MempoolConfig) WalDir() string {
return rootify(m.WalPath, m.RootDir)
func (cfg *MempoolConfig) WalDir() string {
return rootify(cfg.WalPath, cfg.RootDir)
}
//-----------------------------------------------------------------------------
@@ -293,12 +414,11 @@ func (m *MempoolConfig) WalDir() string {
// 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
RootDir string `mapstructure:"home"`
WalPath string `mapstructure:"wal_file"`
walFile string // overrides WalPath if set
// All timeouts are in ms
// All timeouts are in milliseconds
TimeoutPropose int `mapstructure:"timeout_propose"`
TimeoutProposeDelta int `mapstructure:"timeout_propose_delta"`
TimeoutPrevote int `mapstructure:"timeout_prevote"`
@@ -318,11 +438,48 @@ type ConsensusConfig struct {
CreateEmptyBlocks bool `mapstructure:"create_empty_blocks"`
CreateEmptyBlocksInterval int `mapstructure:"create_empty_blocks_interval"`
// Reactor sleep duration parameters are in ms
// 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"),
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
@@ -363,53 +520,57 @@ func (cfg *ConsensusConfig) PeerQueryMaj23Sleep() time.Duration {
return time.Duration(cfg.PeerQueryMaj23SleepDuration) * time.Millisecond
}
// DefaultConsensusConfig returns a default configuration for the consensus service
func DefaultConsensusConfig() *ConsensusConfig {
return &ConsensusConfig{
WalPath: "data/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 {
config := DefaultConsensusConfig()
config.TimeoutPropose = 2000
config.TimeoutProposeDelta = 1
config.TimeoutPrevote = 10
config.TimeoutPrevoteDelta = 1
config.TimeoutPrecommit = 10
config.TimeoutPrecommitDelta = 1
config.TimeoutCommit = 10
config.SkipTimeoutCommit = true
return config
}
// WalFile returns the full path to the write-ahead log file
func (c *ConsensusConfig) WalFile() string {
if c.walFile != "" {
return c.walFile
func (cfg *ConsensusConfig) WalFile() string {
if cfg.walFile != "" {
return cfg.walFile
}
return rootify(c.WalPath, c.RootDir)
return rootify(cfg.WalPath, cfg.RootDir)
}
// SetWalFile sets the path to the write-ahead log file
func (c *ConsensusConfig) SetWalFile(walFile string) {
c.walFile = walFile
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()
}
//-----------------------------------------------------------------------------
@@ -422,3 +583,18 @@ func rootify(path, root string) string {
}
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
}

View File

@@ -1,50 +1,238 @@
package config
import (
"bytes"
"os"
"path"
"path/filepath"
"strings"
"text/template"
cmn "github.com/tendermint/tmlibs/common"
)
/****** these are for production settings ***********/
var configTemplate *template.Template
func EnsureRoot(rootDir string) {
cmn.EnsureDir(rootDir, 0700)
cmn.EnsureDir(rootDir+"/data", 0700)
configFilePath := path.Join(rootDir, "config.toml")
// Write default config file if missing.
if !cmn.FileExists(configFilePath) {
// Ask user for moniker
// moniker := cfg.Prompt("Type hostname: ", "anonymous")
cmn.MustWriteFile(configFilePath, []byte(defaultConfig("anonymous")), 0644)
func init() {
var err error
if configTemplate, err = template.New("configFileTemplate").Parse(defaultConfigTemplate); err != nil {
panic(err)
}
}
var defaultConfigTmpl = `# This is a TOML config file.
/****** 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) {
writeDefaultConfigFile(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 writeDefaultConfigFile(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
proxy_app = "tcp://127.0.0.1:46658"
moniker = "__MONIKER__"
fast_sync = true
db_backend = "leveldb"
log_level = "state:info,*:error"
##### 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 = "{{ js .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 = "{{ js .BaseConfig.Genesis }}"
# Path to the JSON file containing the private key to use as a validator in the consensus protocol
priv_validator_file = "{{ js .BaseConfig.PrivValidator }}"
# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
node_key_file = "{{ js .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]
laddr = "tcp://0.0.0.0:46657"
# 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]
laddr = "tcp://0.0.0.0:46656"
seeds = ""
`
func defaultConfig(moniker string) string {
return strings.Replace(defaultConfigTmpl, "__MONIKER__", moniker, -1)
}
# 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 = "{{ js .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 }}
# 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 = "{{ js .Mempool.WalPath }}"
# size of the mempool
size = {{ .Mempool.Size }}
# size of the cache (used to filter transactions we saw earlier)
cache_size = {{ .Mempool.CacheSize }}
##### consensus configuration options #####
[consensus]
wal_file = "{{ js .Consensus.WalPath }}"
# 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 ***********/
@@ -53,30 +241,35 @@ func ResetTestRoot(testName string) *Config {
rootDir = filepath.Join(rootDir, testName)
// Remove ~/.tendermint_test_bak
if cmn.FileExists(rootDir + "_bak") {
err := os.RemoveAll(rootDir + "_bak")
if err != nil {
if err := os.RemoveAll(rootDir + "_bak"); err != nil {
cmn.PanicSanity(err.Error())
}
}
// Move ~/.tendermint_test to ~/.tendermint_test_bak
if cmn.FileExists(rootDir) {
err := os.Rename(rootDir, rootDir+"_bak")
if err != nil {
if err := os.Rename(rootDir, rootDir+"_bak"); err != nil {
cmn.PanicSanity(err.Error())
}
}
// Create new dir
cmn.EnsureDir(rootDir, 0700)
cmn.EnsureDir(rootDir+"/data", 0700)
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 := path.Join(rootDir, "config.toml")
genesisFilePath := path.Join(rootDir, "genesis.json")
privFilePath := path.Join(rootDir, "priv_validator.json")
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) {
// Ask user for moniker
cmn.MustWriteFile(configFilePath, []byte(testConfig("anonymous")), 0644)
writeDefaultConfigFile(configFilePath)
}
if !cmn.FileExists(genesisFilePath) {
cmn.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644)
@@ -88,36 +281,14 @@ func ResetTestRoot(testName string) *Config {
return config
}
var testConfigTmpl = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
proxy_app = "dummy"
moniker = "__MONIKER__"
fast_sync = false
db_backend = "memdb"
log_level = "info"
[rpc]
laddr = "tcp://0.0.0.0:36657"
[p2p]
laddr = "tcp://0.0.0.0:36656"
seeds = ""
`
func testConfig(moniker string) (testConfig string) {
testConfig = strings.Replace(testConfigTmpl, "__MONIKER__", moniker, -1)
return
}
var testGenesis = `{
"genesis_time": "0001-01-01T00:00:00.000Z",
"chain_id": "tendermint_test",
"validators": [
{
"pub_key": {
"type": "ed25519",
"data":"3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
"type": "AC26791624DE60",
"value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
},
"power": 10,
"name": ""
@@ -127,14 +298,14 @@ var testGenesis = `{
}`
var testPrivValidator = `{
"address": "D028C9981F7A87F3093672BF0D5B0E2A1B3ED456",
"address": "849CB2C877F87A20925F35D00AE6688342D25B47",
"pub_key": {
"type": "ed25519",
"data": "3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
"type": "AC26791624DE60",
"value": "AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
},
"priv_key": {
"type": "ed25519",
"data": "27F82582AEFAE7AB151CFB01C48BB6C1A0DA78F9BDDA979A9F70A84D074EB07D3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
"type": "954568A3288910",
"value": "EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ=="
},
"last_height": 0,
"last_round": 0,

View File

@@ -4,6 +4,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -19,26 +20,29 @@ func ensureFiles(t *testing.T, rootDir string, files ...string) {
}
func TestEnsureRoot(t *testing.T) {
assert, require := assert.New(t), require.New(t)
require := require.New(t)
// setup temp dir for test
tmpDir, err := ioutil.TempDir("", "config-test")
require.Nil(err)
defer os.RemoveAll(tmpDir)
defer os.RemoveAll(tmpDir) // nolint: errcheck
// create root dir
EnsureRoot(tmpDir)
// make sure config is set properly
data, err := ioutil.ReadFile(filepath.Join(tmpDir, "config.toml"))
data, err := ioutil.ReadFile(filepath.Join(tmpDir, defaultConfigFilePath))
require.Nil(err)
assert.Equal([]byte(defaultConfig("anonymous")), data)
if !checkConfig(string(data)) {
t.Fatalf("config file missing some information")
}
ensureFiles(t, tmpDir, "data")
}
func TestEnsureTestRoot(t *testing.T) {
assert, require := assert.New(t), require.New(t)
require := require.New(t)
testName := "ensureTestRoot"
@@ -47,11 +51,44 @@ func TestEnsureTestRoot(t *testing.T) {
rootDir := cfg.RootDir
// make sure config is set properly
data, err := ioutil.ReadFile(filepath.Join(rootDir, "config.toml"))
data, err := ioutil.ReadFile(filepath.Join(rootDir, defaultConfigFilePath))
require.Nil(err)
assert.Equal([]byte(testConfig("anonymous")), data)
if !checkConfig(string(data)) {
t.Fatalf("config file missing some information")
}
// TODO: make sure the cfg returned and testconfig are the same!
ensureFiles(t, rootDir, "data", "genesis.json", "priv_validator.json")
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,18 +1 @@
# The core consensus algorithm.
* state.go - The state machine as detailed in the whitepaper
* reactor.go - A reactor that connects the state machine to the gossip network
# Go-routine summary
The reactor runs 2 go-routines for each added peer: gossipDataRoutine and gossipVotesRoutine.
The consensus state runs two persistent go-routines: timeoutRoutine and receiveRoutine.
Go-routines are also started to trigger timeouts and to avoid blocking when the internalMsgQueue is really backed up.
# Replay/WAL
A write-ahead log is used to record all messages processed by the receiveRoutine,
which amounts to all inputs to the consensus state machine:
messages from peers, messages from ourselves, and timeouts.
They can be played back deterministically at startup or using the replay console.
See the [consensus spec](https://github.com/tendermint/tendermint/tree/master/docs/spec/consensus) and the [reactor consensus spec](https://github.com/tendermint/tendermint/tree/master/docs/spec/reactors/consensus) for more information.

View File

@@ -1,16 +1,15 @@
package consensus
import (
"context"
"sync"
"testing"
"time"
crypto "github.com/tendermint/go-crypto"
data "github.com/tendermint/go-wire/data"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/events"
)
func init() {
@@ -28,11 +27,13 @@ func init() {
// Heal partition and ensure A sees the commit
func TestByzantine(t *testing.T) {
N := 4
logger := consensusLogger()
logger := consensusLogger().With("test", "byzantine")
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")
@@ -41,7 +42,44 @@ func TestByzantine(t *testing.T) {
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 := css[i].eventBus
eventBus.SetLogger(logger.With("module", "events", "validator", i))
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 {
@@ -51,40 +89,6 @@ func TestByzantine(t *testing.T) {
}
}
}()
eventChans := make([]chan interface{}, N)
eventLogger := logger.With("module", "events")
for i := 0; i < N; i++ {
if i == 0 {
css[i].privValidator = NewByzantinePrivValidator(css[i].privValidator)
// make byzantine
css[i].decideProposal = func(j int) func(int, int) {
return func(height, round int) {
byzantineDecideProposalFunc(t, height, round, css[j], switches[j])
}
}(i)
css[i].doPrevote = func(height, round int) {}
}
eventSwitch := events.NewEventSwitch()
eventSwitch.SetLogger(eventLogger.With("validator", i))
_, 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.SetLogger(logger.With("validator", i))
conR.SetEventSwitch(eventSwitch)
var conRI p2p.Reactor
conRI = conR
if i == 0 {
conRI = NewByzantineReactor(conR)
}
reactors[i] = conRI
}
p2p.MakeConnectedSwitches(config.P2P, N, func(i int, s *p2p.Switch) *p2p.Switch {
// ignore new switch s, we already made ours
@@ -98,32 +102,35 @@ func TestByzantine(t *testing.T) {
p2p.Connect2Switches(sws, i, j)
})
// start the state machines
byzR := reactors[0].(*ByzantineReactor)
s := byzR.reactor.conS.GetState()
byzR.reactor.SwitchToConsensus(s)
// start the non-byz state machines.
// note these must be started before the byz
for i := 1; i < N; i++ {
cr := reactors[i].(*ConsensusReactor)
cr.SwitchToConsensus(cr.conS.GetState())
cr.SwitchToConsensus(cr.conS.GetState(), 0)
}
// start the byzantine state machine
byzR := reactors[0].(*ByzantineReactor)
s := byzR.reactor.conS.GetState()
byzR.reactor.SwitchToConsensus(s, 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]
t.Log("A block has been committed. Healing partition")
// connect the partitions
p2p.Connect2Switches(switches, ind0, ind1)
p2p.Connect2Switches(switches, ind0, ind2)
@@ -159,7 +166,7 @@ func TestByzantine(t *testing.T) {
//-------------------------------
// byzantine consensus functions
func byzantineDecideProposalFunc(t *testing.T, 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.
@@ -167,13 +174,17 @@ func byzantineDecideProposalFunc(t *testing.T, height, round int, cs *ConsensusS
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()
@@ -190,10 +201,10 @@ func byzantineDecideProposalFunc(t *testing.T, height, round int, cs *ConsensusS
}
}
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++ {
@@ -203,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
@@ -212,8 +223,8 @@ 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}))
}
//----------------------------------------
@@ -254,47 +265,3 @@ func (br *ByzantineReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
func (br *ByzantineReactor) Receive(chID byte, peer p2p.Peer, msgBytes []byte) {
br.reactor.Receive(chID, peer, msgBytes)
}
//----------------------------------------
// byzantine privValidator
type ByzantinePrivValidator struct {
types.Signer
pv types.PrivValidator
}
// Return a priv validator that will sign anything
func NewByzantinePrivValidator(pv types.PrivValidator) *ByzantinePrivValidator {
return &ByzantinePrivValidator{
Signer: pv.(*types.PrivValidatorFS).Signer,
pv: pv,
}
}
func (privVal *ByzantinePrivValidator) GetAddress() data.Bytes {
return privVal.pv.GetAddress()
}
func (privVal *ByzantinePrivValidator) GetPubKey() crypto.PubKey {
return privVal.pv.GetPubKey()
}
func (privVal *ByzantinePrivValidator) SignVote(chainID string, vote *types.Vote) (err error) {
vote.Signature, err = privVal.Sign(types.SignBytes(chainID, vote))
return err
}
func (privVal *ByzantinePrivValidator) SignProposal(chainID string, proposal *types.Proposal) (err error) {
proposal.Signature, err = privVal.Sign(types.SignBytes(chainID, proposal))
return nil
}
func (privVal *ByzantinePrivValidator) SignHeartbeat(chainID string, heartbeat *types.Heartbeat) (err error) {
heartbeat.Signature, err = privVal.Sign(types.SignBytes(chainID, heartbeat))
return nil
}
func (privVal *ByzantinePrivValidator) String() string {
return cmn.Fmt("PrivValidator{%X}", privVal.GetAddress())
}

View File

@@ -1,35 +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
}
func discardFromChan(ch chan interface{}, n int) {
for i := 0; i < n; i++ {
<-ch
}
}

View File

@@ -2,6 +2,7 @@ package consensus
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
@@ -18,6 +19,7 @@ import (
cstypes "github.com/tendermint/tendermint/consensus/types"
mempl "github.com/tendermint/tendermint/mempool"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/privval"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
@@ -25,14 +27,18 @@ import (
"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"
)
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 * 2
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 := cmn.EnsureDir(dir, mode); err != nil {
@@ -45,16 +51,16 @@ func ResetConfig(name string) *cfg.Config {
}
//-------------------------------------------------------------------------------
// 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
}
var testMinPower = 10
var testMinPower int64 = 10
func NewValidatorStub(privValidator types.PrivValidator, valIndex int) *validatorStub {
return &validatorStub{
@@ -69,10 +75,11 @@ func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartS
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.ChainID, vote)
err := vs.PrivValidator.SignVote(config.ChainID(), vote)
return vote, err
}
@@ -95,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")
@@ -123,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.ChainID, proposal); err != nil {
if err := vs.SignProposal(cs1.state.ChainID, proposal); err != nil {
panic(err)
}
return
@@ -208,12 +215,15 @@ 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
vote := v.(types.TMEventData).Unwrap().(types.EventDataVote)
for v := range voteCh0 {
vote := v.(types.EventDataVote)
// we only fire for our own votes
if bytes.Equal(addr, vote.Vote.ValidatorAddress) {
voteCh <- v
@@ -226,13 +236,17 @@ func subscribeToVoter(cs *ConsensusState, addr []byte) chan interface{} {
//-------------------------------------------------------------------------------
// 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
@@ -247,36 +261,31 @@ func newConsensusStateWithConfig(thisConfig *cfg.Config, state *sm.State, pv typ
mempool.EnableTxsAvailable()
}
// Make ConsensusReactor
cs := NewConsensusState(thisConfig.Consensus, state, proxyAppConnCon, blockStore, mempool)
cs.SetLogger(log.TestingLogger())
// mock the evidence pool
evpool := sm.MockEvidencePool{}
// Make ConsensusState
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()
evsw.SetLogger(log.TestingLogger().With("module", "events"))
cs.SetEventSwitch(evsw)
evsw.Start()
eventBus := types.NewEventBus()
eventBus.SetLogger(log.TestingLogger().With("module", "events"))
eventBus.Start()
cs.SetEventBus(eventBus)
return cs
}
func loadPrivValidator(config *cfg.Config) *types.PrivValidatorFS {
func loadPrivValidator(config *cfg.Config) *privval.FilePV {
privValidatorFile := config.PrivValidatorFile()
ensureDir(path.Dir(privValidatorFile), 0700)
privValidator := types.LoadOrGenPrivValidatorFS(privValidatorFile)
privValidator := privval.LoadOrGenFilePV(privValidatorFile)
privValidator.Reset()
return privValidator
}
func fixedConsensusStateDummy() *ConsensusState {
stateDB := dbm.NewMemDB()
state, _ := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
state.SetLogger(log.TestingLogger().With("module", "state"))
privValidator := loadPrivValidator(config)
cs := newConsensusState(state, privValidator, dummy.NewDummyApplication())
cs.SetLogger(log.TestingLogger())
return cs
}
func randConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
// Get State
state, privVals := randGenesisState(nValidators, false, 10)
@@ -284,7 +293,6 @@ func randConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
vss := make([]*validatorStub, nValidators)
cs := newConsensusState(state, privVals[0], counter.NewCounterApplication(true))
cs.SetLogger(log.TestingLogger())
for i := 0; i < nValidators; i++ {
vss[i] = NewValidatorStub(privVals[i], i)
@@ -297,7 +305,7 @@ func randConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
//-------------------------------------------------------------------------------
func ensureNoNewStep(stepCh chan interface{}) {
func ensureNoNewStep(stepCh <-chan interface{}) {
timer := time.NewTimer(ensureTimeout)
select {
case <-timer.C:
@@ -307,7 +315,7 @@ func ensureNoNewStep(stepCh chan interface{}) {
}
}
func ensureNewStep(stepCh chan interface{}) {
func ensureNewStep(stepCh <-chan interface{}) {
timer := time.NewTimer(ensureTimeout)
select {
case <-timer.C:
@@ -330,39 +338,40 @@ func consensusLogger() log.Logger {
}
}
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, 10)
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.SetLogger(logger.With("module", "state", "validator", i))
state.Save()
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
css[i] = newConsensusStateWithConfig(thisConfig, state, privVals[i], appFunc())
css[i].SetLogger(logger.With("validator", i))
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.SetLogger(log.TestingLogger().With("module", "state"))
state.Save()
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
@@ -370,19 +379,23 @@ func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerF
privVal = privVals[i]
} else {
_, tempFilePath := cmn.Tempfile("priv_validator_")
privVal = types.GenPrivValidatorFS(tempFilePath)
privVal = privval.GenFilePV(tempFilePath)
}
css[i] = newConsensusStateWithConfig(thisConfig, state, privVal, appFunc())
css[i].SetLogger(log.TestingLogger())
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 {
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
}
}
@@ -393,9 +406,9 @@ func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int {
//-------------------------------------------------------------------------------
// genesis
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []*types.PrivValidatorFS) {
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []types.PrivValidator) {
validators := make([]types.GenesisValidator, numValidators)
privValidators := make([]*types.PrivValidatorFS, numValidators)
privValidators := make([]types.PrivValidator, numValidators)
for i := 0; i < numValidators; i++ {
val, privVal := types.RandValidator(randPower, minPower)
validators[i] = types.GenesisValidator{
@@ -405,19 +418,19 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
privValidators[i] = privVal
}
sort.Sort(types.PrivValidatorsByAddress(privValidators))
return &types.GenesisDoc{
GenesisTime: time.Now(),
ChainID: config.ChainID,
ChainID: config.ChainID(),
Validators: validators,
}, privValidators
}
func randGenesisState(numValidators int, randPower bool, minPower int64) (*sm.State, []*types.PrivValidatorFS) {
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.SetLogger(log.TestingLogger().With("module", "state"))
s0.Save()
sm.SaveState(db, s0)
return s0, privValidators
}
@@ -443,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) {
@@ -476,7 +489,7 @@ 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

@@ -2,46 +2,49 @@ package consensus
import (
"encoding/binary"
"fmt"
"testing"
"time"
abci "github.com/tendermint/abci/types"
"github.com/tendermint/tendermint/types"
"github.com/stretchr/testify/assert"
"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 = ResetConfig("consensus_mempool_test")
}
func TestNoProgressUntilTxsAvailable(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 := subscribeToEvent(cs.evsw, "tester", types.EventStringNewBlock(), 1)
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
startTestRound(cs, height, round)
ensureNewStep(newBlockCh) // first block gets committed
ensureNoNewStep(newBlockCh)
deliverTxsRange(cs, 0, 2)
deliverTxsRange(cs, 0, 1)
ensureNewStep(newBlockCh) // commit txs
ensureNewStep(newBlockCh) // commit updated app hash
ensureNoNewStep(newBlockCh)
}
func TestProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
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 := subscribeToEvent(cs.evsw, "tester", types.EventStringNewBlock(), 1)
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
startTestRound(cs, height, round)
ensureNewStep(newBlockCh) // first block gets committed
@@ -49,16 +52,16 @@ func TestProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
ensureNewStep(newBlockCh) // until the CreateEmptyBlocksInterval has passed
}
func TestProgressInHigherRound(t *testing.T) {
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 := subscribeToEvent(cs.evsw, "tester", types.EventStringNewBlock(), 1)
newRoundCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewRound(), 1)
timeoutCh := subscribeToEvent(cs.evsw, "tester", types.EventStringTimeoutPropose(), 1)
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
@@ -73,7 +76,7 @@ func TestProgressInHigherRound(t *testing.T) {
ensureNewStep(newRoundCh) // first round at first height
ensureNewStep(newBlockCh) // first block gets committed
ensureNewStep(newRoundCh) // first round at next height
deliverTxsRange(cs, 0, 2) // we deliver txs, but dont set a proposal so we get the next round
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
@@ -91,29 +94,29 @@ func deliverTxsRange(cs *ConsensusState, start, end int) {
}
}
func TestTxConcurrentWithCommit(t *testing.T) {
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)
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
NTxs := 10000
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.TMEventData).Unwrap().(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)
@@ -121,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")
@@ -164,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")
@@ -187,33 +193,40 @@ 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(cmn.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,17 +1,26 @@
package consensus
import (
"context"
"fmt"
"os"
"runtime"
"runtime/pprof"
"sync"
"testing"
"time"
"github.com/tendermint/abci/example/dummy"
"github.com/tendermint/tmlibs/events"
"github.com/tendermint/abci/example/kvstore"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
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/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func init() {
@@ -21,60 +30,64 @@ func init() {
//----------------------------------------------
// 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)
logger := consensusLogger()
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(logger.With("validator", i))
reactors[i].SetLogger(css[i].Logger)
eventSwitch := events.NewEventSwitch()
eventSwitch.SetLogger(logger.With("module", "events", "validator", i))
_, 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(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)
}
@@ -85,36 +98,146 @@ func TestReactorProposalHeartbeats(t *testing.T) {
func(c *cfg.Config) {
c.Consensus.CreateEmptyBlocks = false
})
reactors, eventChans := startConsensusNet(t, css, N, false)
defer stopConsensusNet(reactors)
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] = subscribeToEvent(css[i].evsw, "tester", types.EventStringProposalHeartbeat(), 1)
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(wg *sync.WaitGroup, j int) {
timeoutWaitGroup(t, N, func(j int) {
<-heartbeatChans[j]
wg.Done()
}, css)
// send a tx
css[3].mempool.CheckTx([]byte{1, 2, 3}, nil)
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(wg *sync.WaitGroup, j int) {
timeoutWaitGroup(t, N, func(j int) {
<-eventChans[j]
wg.Done()
}, 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{})
@@ -123,21 +246,20 @@ 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)
//---------------------------------------------------------------------------
t.Log("---------------------------- 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.GetPubKey()
updateValidatorTx := dummy.MakeValSetChangeTx(val1PubKey.Bytes(), 25)
val1PubKeyABCI := types.TM2PB.PubKey(val1PubKey)
updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKeyABCI, 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)
@@ -145,11 +267,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(val1PubKeyABCI, 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)
@@ -157,11 +279,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(val1PubKeyABCI, 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)
@@ -170,12 +292,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{})
@@ -184,17 +309,16 @@ 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)
//---------------------------------------------------------------------------
t.Log("---------------------------- Testing adding one validator")
logger.Info("---------------------------- Testing adding one validator")
newValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
newValidatorTx1 := dummy.MakeValSetChangeTx(newValidatorPubKey1.Bytes(), uint64(testMinPower))
valPubKey1ABCI := types.TM2PB.PubKey(newValidatorPubKey1)
newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower)
// wait till everyone makes block 2
// ensure the commit includes all validators
@@ -203,7 +327,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
@@ -214,52 +338,55 @@ 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)
//---------------------------------------------------------------------------
t.Log("---------------------------- Testing changing the voting power of one validator")
logger.Info("---------------------------- Testing changing the voting power of one validator")
updateValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
updateValidatorTx1 := dummy.MakeValSetChangeTx(updateValidatorPubKey1.Bytes(), 25)
updatePubKey1ABCI := types.TM2PB.PubKey(updateValidatorPubKey1)
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 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())
}
//---------------------------------------------------------------------------
t.Log("---------------------------- Testing adding two validators at once")
logger.Info("---------------------------- Testing adding two validators at once")
newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey()
newValidatorTx2 := dummy.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), uint64(testMinPower))
newVal2ABCI := types.TM2PB.PubKey(newValidatorPubKey2)
newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower)
newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey()
newValidatorTx3 := dummy.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), uint64(testMinPower))
newVal3ABCI := types.TM2PB.PubKey(newValidatorPubKey3)
newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 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)
//---------------------------------------------------------------------------
t.Log("---------------------------- 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(newVal2ABCI, 0)
removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 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
@@ -271,31 +398,86 @@ func TestReactorWithTimeoutCommit(t *testing.T) {
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.TMEventData).Unwrap().(types.EventDataNewBlock).Block
t.Logf("[WARN] Got block height=%v validator=%v", newBlock.Height, 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()
}, 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)
}
@@ -313,11 +495,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{})
@@ -326,15 +511,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,18 +2,18 @@ package consensus
import (
"bytes"
"errors"
"fmt"
"hash/crc32"
"io"
"reflect"
"strconv"
"strings"
//"strconv"
//"strings"
"time"
abci "github.com/tendermint/abci/types"
wire "github.com/tendermint/go-wire"
auto "github.com/tendermint/tmlibs/autofile"
//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"
@@ -22,31 +22,30 @@ import (
"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,
// which ultimately hands off the work to the WAL.
// There are two general failure scenarios:
//
// 1. failure during consensus
// 2. failure while applying the block
//
// The former is handled by the WAL, the latter by the proxyApp Handshake on
// restart, which ultimately hands off the work to the WAL.
//-----------------------------------------
// recover from failure during consensus
// by replaying messages from the WAL
// 1. Recover from failure during consensus
// (by replaying messages from the WAL)
//-----------------------------------------
// Unmarshal and apply a single message to the consensus state
// 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] == '#' {
// Unmarshal and apply a single message to the consensus state as if it were
// received in receiveRoutine. Lines that start with "#" are ignored.
// NOTE: receiveRoutine should not be running.
func (cs *ConsensusState) readReplayMessage(msg *TimedWALMessage, newStepCh chan interface{}) error {
// Skip meta messages which exist for demarcating boundaries.
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) {
@@ -66,21 +65,21 @@ 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
cs.Logger.Info("Replay: Proposal", "height", p.Height, "round", p.Round, "header",
p.BlockPartsHeader, "pol", p.POLRound, "peer", peerKey)
p.BlockPartsHeader, "pol", p.POLRound, "peer", peerID)
case *BlockPartMessage:
cs.Logger.Info("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
cs.Logger.Info("Replay: Vote", "height", v.Height, "round", v.Round, "type", v.Type,
"blockID", v.BlockID, "peer", peerKey)
"blockID", v.BlockID, "peer", peerID)
}
cs.handleMsg(m)
@@ -93,53 +92,67 @@ func (cs *ConsensusState) readReplayMessage(msgBytes []byte, newStepCh chan inte
return nil
}
// replay only those messages since the last block.
// timeoutRoutine should run concurrently to read off tickChan
func (cs *ConsensusState) catchupReplay(csHeight int) error {
// Replay only those messages since the last block. `timeoutRoutine` should
// run concurrently to read off tickChan.
func (cs *ConsensusState) catchupReplay(csHeight int64) error {
// set replayMode
// Set replayMode to true so we don't log signing errors.
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(cmn.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))
// Search for last height marker.
//
// 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 {
cs.Logger.Error("Replay: wal.group.Search returned EOF", "#ENDHEIGHT", csHeight-1)
} else if err != nil {
return err
} else {
defer gr.Close()
}
if !found {
return errors.New(cmn.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
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
}
}
@@ -151,7 +164,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, " ")
@@ -170,23 +184,35 @@ func makeHeightSearchFunc(height int) auto.SearchFunc {
return -1, nil
}
}
}
}*/
//----------------------------------------------
// Recover from failure during block processing
// by handshaking with the app to figure out where
// we were last and using the WAL to recover there
//---------------------------------------------------
// 2. Recover from failure while applying the block.
// (by handshaking with the app to figure out where
// we were last, and using the WAL to recover there.)
//---------------------------------------------------
type Handshaker struct {
state *sm.State
store types.BlockStore
logger log.Logger
stateDB dbm.DB
initialState sm.State
store sm.BlockStore
genDoc *types.GenesisDoc
logger log.Logger
nBlocks int // number of blocks applied to the state
}
func NewHandshaker(state *sm.State, store types.BlockStore) *Handshaker {
return &Handshaker{state, store, log.NewNopLogger(), 0}
func NewHandshaker(stateDB dbm.DB, state sm.State,
store sm.BlockStore, genDoc *types.GenesisDoc) *Handshaker {
return &Handshaker{
stateDB: stateDB,
initialState: state,
store: store,
genDoc: genDoc,
logger: log.NewNopLogger(),
nBlocks: 0,
}
}
func (h *Handshaker) SetLogger(l log.Logger) {
@@ -199,26 +225,31 @@ func (h *Handshaker) NBlocks() int {
// 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
// Handshake is done via ABCI Info on the query conn.
res, err := proxyApp.Query().InfoSync(abci.RequestInfo{version.Version})
if err != nil {
return errors.New(cmn.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
h.logger.Info("ABCI Handshake", "appHeight", blockHeight, "appHash", fmt.Sprintf("%X", appHash))
// TODO: check version
// TODO: check app version.
// replay blocks up to the latest in the blockstore
_, err = h.ReplayBlocks(appHash, blockHeight, proxyApp)
// Replay blocks up to the latest in the blockstore.
_, err = h.ReplayBlocks(h.initialState, appHash, blockHeight, proxyApp)
if err != nil {
return errors.New(cmn.Fmt("Error on replay: %v", err))
return fmt.Errorf("Error on replay: %v", err)
}
h.logger.Info("Completed ABCI Handshake - Tendermint and App are synced", "appHeight", blockHeight, "appHash", fmt.Sprintf("%X", appHash))
h.logger.Info("Completed ABCI Handshake - Tendermint and App are synced",
"appHeight", blockHeight, "appHash", fmt.Sprintf("%X", appHash))
// TODO: (on restart) replay mempool
@@ -226,22 +257,48 @@ 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) {
// Returns the final AppHash or an 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
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(h.state.Validators)
proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators})
validators := types.TM2PB.Validators(state.Validators)
csParams := types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams)
req := abci.RequestInitChain{
Time: h.genDoc.GenesisTime.Unix(), // TODO
ChainId: h.genDoc.ChainID,
ConsensusParams: csParams,
Validators: validators,
AppStateBytes: h.genDoc.AppStateJSON,
}
res, err := proxyApp.Consensus().InitChainSync(req)
if err != nil {
return nil, err
}
// if the app returned validators
// or consensus params, update the state
// with the them
if len(res.Validators) > 0 {
vals, err := types.PB2TM.Validators(res.Validators)
if err != nil {
return nil, err
}
state.Validators = types.NewValidatorSet(vals)
}
if res.ConsensusParams != nil {
state.ConsensusParams = types.PB2TM.ConsensusParams(res.ConsensusParams)
}
sm.SaveState(h.stateDB, state)
}
// 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)
@@ -256,6 +313,7 @@ func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int, proxyApp p
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 {
@@ -263,11 +321,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 {
@@ -276,22 +334,27 @@ 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
// but we'd have to allow the WAL to replay a block that wrote it's #ENDHEIGHT
h.logger.Info("Replay last block using real app")
return h.replayBlock(storeBlockHeight, proxyApp.Consensus())
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)
h.logger.Info("Replay last block using mock app")
return h.replayBlock(storeBlockHeight, mockApp)
state, err = h.replayBlock(state, storeBlockHeight, mockApp)
return state.AppHash, err
}
}
@@ -300,13 +363,14 @@ func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int, proxyApp p
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()
@@ -314,48 +378,52 @@ func (h *Handshaker) replayBlocks(proxyApp proxy.AppConns, appBlockHeight, store
var err error
finalBlock := storeBlockHeight
if mutateState {
finalBlock -= 1
finalBlock--
}
for i := appBlockHeight + 1; i <= finalBlock; i++ {
h.logger.Info("Applying block", "height", i)
block := h.store.LoadBlock(i)
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger)
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger, state.LastValidators, h.stateDB)
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, sm.MockMempool{}, sm.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(cmn.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
}
@@ -370,7 +438,10 @@ func newMockProxyApp(appHash []byte, abciResponses *sm.ABCIResponses) proxy.AppC
abciResponses: abciResponses,
})
cli, _ := clientCreator.NewABCIClient()
cli.Start()
err := cli.Start()
if err != nil {
panic(err)
}
return proxy.NewAppConnConsensus(cli)
}
@@ -382,21 +453,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,12 +2,15 @@ package consensus
import (
"bufio"
"errors"
"context"
"fmt"
"io"
"os"
"strconv"
"strings"
"github.com/pkg/errors"
bc "github.com/tendermint/tendermint/blockchain"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/proxy"
@@ -15,11 +18,18 @@ import (
"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
// replay the wal file
func RunReplayFile(config cfg.BaseConfig, csConfig *cfg.ConsensusConfig, console bool) {
consensusState := newConsensusStateForReplay(config, csConfig)
@@ -41,31 +51,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
}
@@ -76,51 +101,60 @@ 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
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
}
@@ -164,13 +198,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":
@@ -180,10 +213,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 {
@@ -191,7 +234,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)
}
}
}
@@ -218,7 +263,7 @@ func (pb *playback) replayConsoleLoop() int {
case "locked_block":
fmt.Printf("%v %v\n", rs.LockedBlockParts.StringShort(), rs.LockedBlock.StringShort())
case "votes":
fmt.Println(rs.Votes.StringIndented(" "))
fmt.Println(rs.Votes.StringIndented(" "))
default:
fmt.Println("Unknown option", tokens[1])
@@ -235,33 +280,42 @@ func (pb *playback) replayConsoleLoop() int {
// convenience for replay mode
func newConsensusStateForReplay(config cfg.BaseConfig, csConfig *cfg.ConsensusConfig) *ConsensusState {
dbType := dbm.DBBackendType(config.DBBackend)
// Get BlockStore
blockStoreDB := dbm.NewDB("blockstore", config.DBBackend, config.DBDir())
blockStoreDB := dbm.NewDB("blockstore", dbType, config.DBDir())
blockStore := bc.NewBlockStore(blockStoreDB)
// Get State
stateDB := dbm.NewDB("state", config.DBBackend, config.DBDir())
state, err := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
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)
clientCreator := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir())
proxyApp := proxy.NewAppConns(clientCreator, NewHandshaker(state, blockStore))
_, err = proxyApp.Start()
proxyApp := proxy.NewAppConns(clientCreator,
NewHandshaker(stateDB, state, blockStore, gdoc))
err = proxyApp.Start()
if err != nil {
cmn.Exit(cmn.Fmt("Error starting proxy app conns: %v", err))
}
// Make event switch
eventSwitch := types.NewEventSwitch()
if _, err := eventSwitch.Start(); err != nil {
cmn.Exit(cmn.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))
}
consensusState := NewConsensusState(csConfig, state.Copy(), proxyApp.Consensus(), blockStore, types.MockMempool{})
mempool, evpool := sm.MockMempool{}, sm.MockEvidencePool{}
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
consensusState.SetEventSwitch(eventSwitch)
consensusState := NewConsensusState(csConfig, state.Copy(), blockExec,
blockStore, mempool, evpool)
consensusState.SetEventBus(eventBus)
return consensusState
}

View File

@@ -2,32 +2,39 @@ package consensus
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"strings"
"runtime"
"testing"
"time"
"github.com/tendermint/abci/example/dummy"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/abci/example/kvstore"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
wire "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/privval"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/log"
)
var consensusReplayConfig *cfg.Config
func init() {
config = 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.
@@ -38,14 +45,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!
// NOTE: Files in this dir are generated by running the `build.sh` therein.
// It's a simple way to generate wals for a single block, or multiple blocks, with random transactions,
// and different part sizes. The output is not deterministic, and the stepChanges may need to be adjusted
// after running it (eg. sometimes small_block2 will have 5 block parts, sometimes 6).
// It should only have to be re-run if there is some breaking change to the consensus data structures (eg. blocks, votes)
// or to the behaviour of the app (eg. computes app hash differently)
var data_dir = path.Join(cmn.GoPath, "src/github.com/tendermint/tendermint/consensus", "test_data")
//------------------------------------------------------------------------------------------
// WAL Tests
@@ -53,221 +52,220 @@ 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, 11, 13}), // small block with txs across 6 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.SetWalFile(walFile)
started, err := cs.Start()
if err != nil {
t.Fatalf("Cannot start consensus: %v", err)
// 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},
}
if !started {
t.Error("Consensus did not start")
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
crashWALandCheckLiveness(t, tc.initFn, tc.heightToStop)
})
}
// 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()
}
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 types.PrivValidator) *types.PrivValidatorFS {
return pv.(*types.PrivValidatorFS)
}
// make sure we can make blocks after a crash
startNewConsensusStateAndWaitForBlock(t, cs.Height, blockDB, stateDB)
func setupReplayTest(t *testing.T, thisCase *testCase, nLines int, crashAfter bool) (*ConsensusState, chan interface{}, string, string) {
t.Log("-------------------------------------")
t.Logf("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]
t.Logf("[WARN] setupReplayTest LastStep=%v", 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(t, 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(t, 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)
}
// Write simulate WAL's crashing by sending an error to the panicCh and then
// exiting the cs.receiveRoutine.
func (w *crashingWAL) Write(m WALMessage) {
if endMsg, ok := m.(EndHeightMessage); ok {
if endMsg.Height == w.heightToStop {
w.panicCh <- ReachedHeightToStopError{endMsg.Height}
runtime.Goexit()
} else {
w.next.Write(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.Write(m)
}
}
func TestWALCrashBeforeWritePrevote(t *testing.T) {
for _, thisCase := range testCases {
testReplayCrashBeforeWriteVote(t, thisCase, thisCase.prevoteLine, types.EventStringCompleteProposal())
}
func (w *crashingWAL) WriteSync(m WALMessage) {
w.Write(m)
}
func TestWALCrashBeforeWritePrecommit(t *testing.T) {
for _, thisCase := range testCases {
testReplayCrashBeforeWriteVote(t, thisCase, thisCase.precommitLine, types.EventStringPolka())
}
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 testReplayCrashBeforeWriteVote(t *testing.T, thisCase *testCase, lineNum int, eventString string) {
// setup replay test where last message is a vote
cs, newBlockCh, voteMsg, walFile := setupReplayTest(t, 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
const (
NUM_BLOCKS = 6
)
var (
NUM_BLOCKS = 6 // number of blocks in the test_data/many_blocks.cswal
mempool = types.MockMempool{}
mempool = sm.MockMempool{}
evpool = sm.MockEvidencePool{}
)
//---------------------------------------
@@ -306,57 +304,76 @@ 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 := 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))
walFile := tempWALWithData(walBody)
config.Consensus.SetWalFile(walFile)
privVal := types.LoadPrivValidatorFS(config.PrivValidatorFile())
privVal := privval.LoadFilePV(config.PrivValidatorFile())
wal, err := NewWAL(walFile, false)
wal, err := NewWAL(walFile)
if err != nil {
t.Fatal(err)
}
wal.SetLogger(log.TestingLogger())
if _, err := wal.Start(); err != nil {
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.GetPubKey())
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.DBDir(), "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(clientCreator2, nil)
state, _ := stateAndStore(config, privVal.GetPubKey())
buildAppStateFromChain(proxyApp, state, chain, nBlocks, mode)
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(state, store)
genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile())
handshaker := NewHandshaker(stateDB, state, store, genDoc)
proxyApp := proxy.NewAppConns(clientCreator2, handshaker)
if _, err := proxyApp.Start(); err != nil {
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(abci.RequestInfo{""})
@@ -371,9 +388,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 {
@@ -381,189 +398,208 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
}
}
func applyBlock(st *sm.State, blk *types.Block, proxyApp proxy.AppConns) {
testPartSize := st.Params().BlockPartSizeBytes
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()
validators := types.TM2PB.Validators(state.Validators)
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{
Validators: validators,
}); err != nil {
panic(err)
}
validators := types.TM2PB.Validators(state.Validators)
proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators})
defer proxyApp.Stop()
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.DBDir(), "1")))
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 {
if err := proxyApp.Start(); err != nil {
panic(err)
}
defer proxyApp.Stop()
validators := types.TM2PB.Validators(state.Validators)
proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators})
var latestAppHash []byte
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{
Validators: validators,
}); 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")
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(), 0, &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)
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(), 0, &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
}
case EndHeightMessage:
return m
}
return nil, nil
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()
state, _ := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
state.SetLogger(log.TestingLogger().With("module", "state"))
store := NewMockBlockStore(config, state.Params())
return state, store
state, _ := sm.MakeGenesisStateFromFile(config.GenesisFile())
store := NewMockBlockStore(config, state.ConsensusParams)
return stateDB, state, store
}
//----------------------------------
@@ -581,21 +617,71 @@ func NewMockBlockStore(config *cfg.Config, params types.ConsensusParams) *mockBl
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.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]
}
//----------------------------------------
func TestInitChainUpdateValidators(t *testing.T) {
val, _ := types.RandValidator(true, 10)
vals := types.NewValidatorSet([]*types.Validator{val})
app := &initChainApp{vals: types.TM2PB.Validators(vals)}
clientCreator := proxy.NewLocalClientCreator(app)
config := ResetConfig("proxy_test_")
privVal := privval.LoadFilePV(config.PrivValidatorFile())
stateDB, state, store := stateAndStore(config, privVal.GetPubKey())
oldValAddr := state.Validators.Validators[0].Address
// now start the app using the handshake - it should sync
genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile())
handshaker := NewHandshaker(stateDB, state, store, genDoc)
proxyApp := proxy.NewAppConns(clientCreator, handshaker)
if err := proxyApp.Start(); err != nil {
t.Fatalf("Error starting proxy app connections: %v", err)
}
defer proxyApp.Stop()
// reload the state, check the validator set was updated
state = sm.LoadState(stateDB)
newValAddr := state.Validators.Validators[0].Address
expectValAddr := val.Address
assert.NotEqual(t, oldValAddr, newValAddr)
assert.Equal(t, newValAddr, expectValAddr)
}
func newInitChainApp(vals []abci.Validator) *initChainApp {
return &initChainApp{
vals: vals,
}
}
// returns the vals on InitChain
type initChainApp struct {
abci.BaseApplication
vals []abci.Validator
}
func (ica *initChainApp) InitChain(req abci.RequestInitChain) abci.ResponseInitChain {
return abci.ResponseInitChain{
Validators: ica.vals,
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,13 +2,16 @@ package consensus
import (
"bytes"
"context"
"fmt"
"testing"
"time"
cstypes "github.com/tendermint/tendermint/consensus/types"
tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
)
func init() {
@@ -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)
@@ -86,10 +89,10 @@ func TestProposerSelection0(t *testing.T) {
}
// 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:]...)
@@ -115,13 +118,13 @@ 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)
@@ -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)
@@ -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 := cs1.state.Params().BlockPartSizeBytes
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.ChainID, 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.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.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 := cs1.state.Params().BlockPartSizeBytes
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.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
@@ -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.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.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
@@ -429,7 +440,7 @@ func TestLockNoPOL(t *testing.T) {
incrementRound(vs2)
re = <-proposalCh
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.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()) {
@@ -469,7 +480,9 @@ func TestLockNoPOL(t *testing.T) {
// 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,18 +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 := cs1.state.Params().BlockPartSizeBytes
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)
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
@@ -516,7 +529,7 @@ func TestLockPOLRelock(t *testing.T) {
<-newRoundCh
re := <-proposalCh
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
@@ -546,7 +559,9 @@ func TestLockPOLRelock(t *testing.T) {
<-timeoutWaitCh
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
<-newRoundCh
t.Log("### ONTO ROUND 1")
@@ -590,9 +605,9 @@ func TestLockPOLRelock(t *testing.T) {
discardFromChan(voteCh, 2)
be := <-newBlockCh
b := be.(types.TMEventData).Unwrap().(types.EventDataNewBlockHeader)
b := be.(types.EventDataNewBlockHeader)
re = <-newRoundCh
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
if rs.Height != 2 {
panic("Expected height to increment")
}
@@ -603,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 := cs1.state.Params().BlockPartSizeBytes
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
@@ -628,7 +643,7 @@ func TestLockPOLUnlock(t *testing.T) {
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
re := <-proposalCh
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
@@ -654,11 +669,13 @@ func TestLockPOLUnlock(t *testing.T) {
// timeout to new round
re = <-timeoutWaitCh
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
lockedBlockHash := rs.LockedBlock.Hash()
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
<-newRoundCh
t.Log("#### ONTO ROUND 1")
@@ -698,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 := cs1.state.Params().BlockPartSizeBytes
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.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
propBlock := rs.ProposalBlock
<-voteCh // prevote
@@ -745,7 +762,9 @@ func TestLockPOLSafety1(t *testing.T) {
incrementRound(vs2, vs3, vs4)
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
<-newRoundCh
t.Log("### ONTO ROUND 1")
@@ -762,7 +781,7 @@ func TestLockPOLSafety1(t *testing.T) {
re = <-proposalCh
}
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
if rs.LockedBlock != nil {
panic("we should not be locked!")
@@ -802,7 +821,7 @@ 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...)
@@ -819,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 := cs1.state.Params().BlockPartSizeBytes
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
@@ -857,7 +876,9 @@ func TestLockPOLSafety2(t *testing.T) {
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
@@ -879,10 +900,12 @@ 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.ChainID, 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...)
@@ -914,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
@@ -949,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
@@ -994,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 := cs1.state.Params().BlockPartSizeBytes
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.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
propBlock := rs.ProposalBlock
propBlockParts := propBlock.MakePartSet(partSize)
@@ -1033,7 +1056,7 @@ func TestHalt1(t *testing.T) {
// timeout to new round
<-timeoutWaitCh
re = <-newRoundCh
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
t.Log("### ONTO ROUND 1")
/*Round2
@@ -1051,9 +1074,26 @@ func TestHalt1(t *testing.T) {
// receiving that precommit should take us straight to commit
<-newBlockCh
re = <-newRoundCh
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.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,110 +0,0 @@
#!/usr/bin/env bash
# XXX: removes tendermint dir
cd "$GOPATH/src/github.com/tendermint/tendermint" || exit 1
# Make sure we have a tendermint command.
if ! hash tendermint 2>/dev/null; then
make install
fi
# specify a dir to copy
# TODO: eventually we should replace with `tendermint init --test`
DIR_TO_COPY=$HOME/.tendermint_test/consensus_state_test
TMHOME="$HOME/.tendermint"
rm -rf "$TMHOME"
cp -r "$DIR_TO_COPY" "$TMHOME"
cp $TMHOME/config.toml $TMHOME/config.toml.bak
function reset(){
tendermint unsafe_reset_all
cp $TMHOME/config.toml.bak $TMHOME/config.toml
}
reset
# empty block
function empty_block(){
tendermint node --proxy_app=persistent_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=persistent_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=persistent_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=persistent_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":"2017-04-27T22:24:01.346Z","msg":[3,{"duration":972946821,"height":1,"round":0,"step":1}]}
{"time":"2017-04-27T22:24:01.349Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPropose"}]}
{"time":"2017-04-27T22:24:01.349Z","msg":[2,{"msg":[17,{"Proposal":{"height":1,"round":0,"block_parts_header":{"total":1,"hash":"ACED4A95DDEBD24E66A681F7EAB4CA22C4B8546D"},"pol_round":-1,"pol_block_id":{"hash":"","parts":{"total":0,"hash":""}},"signature":[1,"E785764AED6D92D7CC65C0A3A4ED9C8465198A05142C3E6C7F3EF601FDCD3A604900B77B7B87C046221EF99FD038A960398385BD5BBAA50EE4F86DE757B8F704"]}}],"peer_key":""}]}
{"time":"2017-04-27T22:24:01.350Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":0,"bytes":"0101010F74656E6465726D696E745F74657374010114B96165CF4496C00000000000000114354594CBFC1A7BCA1AD0050ED6AA010023EADA390001000100000000","proof":{"aunts":[]}}}],"peer_key":""}]}
{"time":"2017-04-27T22:24:01.351Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPrevote"}]}
{"time":"2017-04-27T22:24:01.351Z","msg":[2,{"msg":[20,{"Vote":{"validator_address":"D028C9981F7A87F3093672BF0D5B0E2A1B3ED456","validator_index":0,"height":1,"round":0,"type":1,"block_id":{"hash":"F3BBFBE7E4A5D619E2C498C3D1B912883786DD71","parts":{"total":1,"hash":"ACED4A95DDEBD24E66A681F7EAB4CA22C4B8546D"}},"signature":[1,"35C937C78D061ECDC3770982A1330C9AA7F6FEF00835C43DEB50B8FCF69A3EEF221E675EE5E469114F64E4FBBABA414EB9170E1025FC47D3F0EADE46767D2E00"]}}],"peer_key":""}]}
{"time":"2017-04-27T22:24:01.352Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPrecommit"}]}
{"time":"2017-04-27T22:24:01.352Z","msg":[2,{"msg":[20,{"Vote":{"validator_address":"D028C9981F7A87F3093672BF0D5B0E2A1B3ED456","validator_index":0,"height":1,"round":0,"type":2,"block_id":{"hash":"F3BBFBE7E4A5D619E2C498C3D1B912883786DD71","parts":{"total":1,"hash":"ACED4A95DDEBD24E66A681F7EAB4CA22C4B8546D"}},"signature":[1,"D1A7D27FCD5D352F3A3EDA8DE368520BC5B796662E32BCD8D91CDB8209A88DAF37CB7C4C93143D3C12B37C1435229268098CFFD0AD1400D88DA7606454692301"]}}],"peer_key":""}]}
{"time":"2017-04-27T22:24:01.352Z","msg":[1,{"height":1,"round":0,"step":"RoundStepCommit"}]}

File diff suppressed because one or more lines are too long

View File

@@ -1,15 +0,0 @@
#ENDHEIGHT: 0
{"time":"2017-04-27T22:23:56.310Z","msg":[3,{"duration":969732098,"height":1,"round":0,"step":1}]}
{"time":"2017-04-27T22:23:56.312Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPropose"}]}
{"time":"2017-04-27T22:23:56.312Z","msg":[2,{"msg":[17,{"Proposal":{"height":1,"round":0,"block_parts_header":{"total":6,"hash":"A3C176F13F5CBC7C48EE27A472800410C9D487DC"},"pol_round":-1,"pol_block_id":{"hash":"","parts":{"total":0,"hash":""}},"signature":[1,"7624F6E943B7A207E16D1FA87EA099BD924E930F98E7DECBC01DB37735C619409588A67C2EABA9845FD6B80FDB65ECFCDA5F0DEFCEF74B8C34DB8E0540480203"]}}],"peer_key":""}]}
{"time":"2017-04-27T22:23:56.312Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":0,"bytes":"0101010F74656E6465726D696E745F74657374010114B96164A30A118001620000000001141F6753D22BACA2180B1EADD722434EB28444D91D0114354594CBFC1A7BCA1AD0050ED6AA010023EADA3900010162011A3631363236333634333133303344363436333632363133313330011A3631363236333634333133313344363436333632363133313331011A3631363236333634333133323344363436333632363133313332011A3631363236333634333133333344363436333632363133313333011A3631363236333634333133343344363436333632363133313334011A3631363236333634333133353344363436333632363133313335011A3631363236333634333133363344363436333632363133313336011A3631363236333634333133373344363436333632363133313337011A3631363236333634333133383344363436333632363133313338011A3631363236333634333133393344363436333632363133313339011A3631363236333634333233303344363436333632363133323330011A3631363236333634333233313344363436333632363133323331011A3631363236333634333233323344363436333632363133323332011A3631363236333634333233333344363436333632363133323333011A3631363236333634333233343344363436333632363133323334011A36313632363336","proof":{"aunts":["49F4B71E3D7C457415069E2EA916DB12F67AA8D0","D35A72BEDAAAAC17045D7BFAAFA94C2EC0B0A4C2","705BC647374F3495EE73C3F44C21E9BDB4731738"]}}}],"peer_key":""}]}
{"time":"2017-04-27T22:23:56.312Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":1,"bytes":"34333233353344363436333632363133323335011A3631363236333634333233363344363436333632363133323336011A3631363236333634333233373344363436333632363133323337011A3631363236333634333233383344363436333632363133323338011A3631363236333634333233393344363436333632363133323339011A3631363236333634333333303344363436333632363133333330011A3631363236333634333333313344363436333632363133333331011A3631363236333634333333323344363436333632363133333332011A3631363236333634333333333344363436333632363133333333011A3631363236333634333333343344363436333632363133333334011A3631363236333634333333353344363436333632363133333335011A3631363236333634333333363344363436333632363133333336011A3631363236333634333333373344363436333632363133333337011A3631363236333634333333383344363436333632363133333338011A3631363236333634333333393344363436333632363133333339011A3631363236333634333433303344363436333632363133343330011A3631363236333634333433313344363436333632363133343331011A3631363236333634333433323344363436333632363133343332011A363136323633363433343333334436","proof":{"aunts":["5AD2A9A1A49A1FD6EF83F05FA4588F800B29DEF1","D35A72BEDAAAAC17045D7BFAAFA94C2EC0B0A4C2","705BC647374F3495EE73C3F44C21E9BDB4731738"]}}}],"peer_key":""}]}
{"time":"2017-04-27T22:23:56.312Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":2,"bytes":"3436333632363133343333011A3631363236333634333433343344363436333632363133343334011A3631363236333634333433353344363436333632363133343335011A3631363236333634333433363344363436333632363133343336011A3631363236333634333433373344363436333632363133343337011A3631363236333634333433383344363436333632363133343338011A3631363236333634333433393344363436333632363133343339011A3631363236333634333533303344363436333632363133353330011A3631363236333634333533313344363436333632363133353331011A3631363236333634333533323344363436333632363133353332011A3631363236333634333533333344363436333632363133353333011A3631363236333634333533343344363436333632363133353334011A3631363236333634333533353344363436333632363133353335011A3631363236333634333533363344363436333632363133353336011A3631363236333634333533373344363436333632363133353337011A3631363236333634333533383344363436333632363133353338011A3631363236333634333533393344363436333632363133353339011A3631363236333634333633303344363436333632363133363330011A3631363236333634333633313344363436333632363133","proof":{"aunts":["8B5786C3D871EE37B0F4B2DECAC39E157340DFBE","705BC647374F3495EE73C3F44C21E9BDB4731738"]}}}],"peer_key":""}]}
{"time":"2017-04-27T22:23:56.312Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":3,"bytes":"363331011A3631363236333634333633323344363436333632363133363332011A3631363236333634333633333344363436333632363133363333011A3631363236333634333633343344363436333632363133363334011A3631363236333634333633353344363436333632363133363335011A3631363236333634333633363344363436333632363133363336011A3631363236333634333633373344363436333632363133363337011A3631363236333634333633383344363436333632363133363338011A3631363236333634333633393344363436333632363133363339011A3631363236333634333733303344363436333632363133373330011A3631363236333634333733313344363436333632363133373331011A3631363236333634333733323344363436333632363133373332011A3631363236333634333733333344363436333632363133373333011A3631363236333634333733343344363436333632363133373334011A3631363236333634333733353344363436333632363133373335011A3631363236333634333733363344363436333632363133373336011A3631363236333634333733373344363436333632363133373337011A3631363236333634333733383344363436333632363133373338011A3631363236333634333733393344363436333632363133373339011A363136","proof":{"aunts":["56097661A1B2707588100586B3B1C2C8A51057D1","6DE889147DF528EEB5F7422E95DC45900CAFB619","247C721D5CEB90BB1FE389BA74C43DF0955E1647"]}}}],"peer_key":""}]}
{"time":"2017-04-27T22:23:56.312Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":4,"bytes":"3236333634333833303344363436333632363133383330011A3631363236333634333833313344363436333632363133383331011A3631363236333634333833323344363436333632363133383332011A3631363236333634333833333344363436333632363133383333011A3631363236333634333833343344363436333632363133383334011A3631363236333634333833353344363436333632363133383335011A3631363236333634333833363344363436333632363133383336011A3631363236333634333833373344363436333632363133383337011A3631363236333634333833383344363436333632363133383338011A3631363236333634333833393344363436333632363133383339011A3631363236333634333933303344363436333632363133393330011A3631363236333634333933313344363436333632363133393331011A3631363236333634333933323344363436333632363133393332011A3631363236333634333933333344363436333632363133393333011A3631363236333634333933343344363436333632363133393334011A3631363236333634333933353344363436333632363133393335011A3631363236333634333933363344363436333632363133393336011A3631363236333634333933373344363436333632363133393337011A3631363236333634333933","proof":{"aunts":["081D3DC5F11850851D5F0D760B98EE87BFA6B8B0","6DE889147DF528EEB5F7422E95DC45900CAFB619","247C721D5CEB90BB1FE389BA74C43DF0955E1647"]}}}],"peer_key":""}]}
{"time":"2017-04-27T22:23:56.313Z","msg":[2,{"msg":[19,{"Height":1,"Round":0,"Part":{"index":5,"bytes":"383344363436333632363133393338011A3631363236333634333933393344363436333632363133393339011E363136323633363433313330333033443634363336323631333133303330011E363136323633363433313330333133443634363336323631333133303331011E363136323633363433313330333233443634363336323631333133303332011E363136323633363433313330333333443634363336323631333133303333011E363136323633363433313330333433443634363336323631333133303334011E363136323633363433313330333533443634363336323631333133303335011E363136323633363433313330333633443634363336323631333133303336011E3631363236333634333133303337334436343633363236313331333033370100000000","proof":{"aunts":["6AA912328C2B52EFA0ECE71F523E137E400EC484","247C721D5CEB90BB1FE389BA74C43DF0955E1647"]}}}],"peer_key":""}]}
{"time":"2017-04-27T22:23:56.314Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPrevote"}]}
{"time":"2017-04-27T22:23:56.314Z","msg":[2,{"msg":[20,{"Vote":{"validator_address":"D028C9981F7A87F3093672BF0D5B0E2A1B3ED456","validator_index":0,"height":1,"round":0,"type":1,"block_id":{"hash":"62371CF72F8662378691706DB256C833CF1AF81B","parts":{"total":6,"hash":"A3C176F13F5CBC7C48EE27A472800410C9D487DC"}},"signature":[1,"255906FAAA50C84E85DABF7DE73468E4F95DB4E46F598848145926E2FAD77CA682BF07E09E2F3EC81FFBD9A036B67914A3C02F819B69248D777AEBA792725907"]}}],"peer_key":""}]}
{"time":"2017-04-27T22:23:56.315Z","msg":[1,{"height":1,"round":0,"step":"RoundStepPrecommit"}]}
{"time":"2017-04-27T22:23:56.315Z","msg":[2,{"msg":[20,{"Vote":{"validator_address":"D028C9981F7A87F3093672BF0D5B0E2A1B3ED456","validator_index":0,"height":1,"round":0,"type":2,"block_id":{"hash":"62371CF72F8662378691706DB256C833CF1AF81B","parts":{"total":6,"hash":"A3C176F13F5CBC7C48EE27A472800410C9D487DC"}},"signature":[1,"056CC15C748434D0A59B64B45CB56EDC1A437A426E68FA63DC7D61A7C17B0F768F207D81340D129A57C5A64195F8AFDD03B6BF28D7B2286290D61BCE88FCA304"]}}],"peer_key":""}]}
{"time":"2017-04-27T22:23:56.316Z","msg":[1,{"height":1,"round":0,"step":"RoundStepCommit"}]}

View File

@@ -15,8 +15,8 @@ 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
@@ -68,7 +68,7 @@ func (t *timeoutTicker) Chan() <-chan timeoutInfo {
}
// ScheduleTimeout schedules a new timeout by sending on the internal tickChan.
// The timeoutRoutine is alwaya available to read from tickChan, so this won't block.
// 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
@@ -127,7 +127,7 @@ func (t *timeoutTicker) timeoutRoutine() {
// 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,9 +1,12 @@
package types
import (
"errors"
"fmt"
"strings"
"sync"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
@@ -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
@@ -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
}
}
@@ -169,6 +174,26 @@ func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *types.VoteSet {
}
}
// If a peer claims that it has 2/3 majority for given blockKey, call this.
// 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 p2p.ID, blockID types.BlockID) error {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
if !types.IsVoteTypeValid(type_) {
return fmt.Errorf("SetPeerMaj23: Invalid vote type %v", type_)
}
voteSet := hvs.getVoteSet(round, type_)
if voteSet == nil {
return nil // something we don't know about yet
}
return voteSet.SetPeerMaj23(types.P2PID(peerID), blockID)
}
//---------------------------------------------------------
// string and json
func (hvs *HeightVoteSet) String() string {
return hvs.StringIndented("")
}
@@ -202,19 +227,35 @@ func (hvs *HeightVoteSet) StringIndented(indent string) string {
indent)
}
// If a peer claims that it has 2/3 majority for given blockKey, call this.
// 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) MarshalJSON() ([]byte, error) {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
if !types.IsVoteTypeValid(type_) {
return
}
voteSet := hvs.getVoteSet(round, type_)
if voteSet == nil {
return
}
voteSet.SetPeerMaj23(peerID, blockID)
allVotes := hvs.toAllRoundVotes()
return cdc.MarshalJSON(allVotes)
}
func (hvs *HeightVoteSet) toAllRoundVotes() []roundVotes {
totalRounds := hvs.round + 1
allVotes := make([]roundVotes, totalRounds)
// rounds 0 ~ hvs.round inclusive
for round := 0; round < totalRounds; round++ {
allVotes[round] = roundVotes{
Round: round,
Prevotes: hvs.roundVoteSets[round].Prevotes.VoteStrings(),
PrevotesBitArray: hvs.roundVoteSets[round].Prevotes.BitArrayString(),
Precommits: hvs.roundVoteSets[round].Precommits.VoteStrings(),
PrecommitsBitArray: hvs.roundVoteSets[round].Precommits.BitArrayString(),
}
}
// TODO: all other peer catchup rounds
return allVotes
}
type roundVotes struct {
Round int `json:"round"`
Prevotes []string `json:"prevotes"`
PrevotesBitArray string `json:"prevotes_bit_array"`
Precommits []string `json:"precommits"`
PrecommitsBitArray string `json:"precommits_bit_array"`
}

View File

@@ -2,6 +2,7 @@ package types
import (
"testing"
"time"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/types"
@@ -17,7 +18,7 @@ func init() {
func TestPeerCatchupRounds(t *testing.T) {
valSet, privVals := types.RandValidatorSet(10, 1)
hvs := NewHeightVoteSet(config.ChainID, 1, valSet)
hvs := NewHeightVoteSet(config.ChainID(), 1, valSet)
vote999_0 := makeVoteHR(t, 1, 999, privVals, 0)
added, err := hvs.AddVote(vote999_0, "peer1")
@@ -33,8 +34,8 @@ func TestPeerCatchupRounds(t *testing.T) {
vote1001_0 := makeVoteHR(t, 1, 1001, privVals, 0)
added, err = hvs.AddVote(vote1001_0, "peer1")
if err != nil {
t.Error("AddVote error", err)
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.")
@@ -47,17 +48,18 @@ func TestPeerCatchupRounds(t *testing.T) {
}
func makeVoteHR(t *testing.T, height, round int, privVals []*types.PrivValidatorFS, 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.GetAddress(),
ValidatorIndex: valIndex,
Height: height,
Round: round,
Timestamp: time.Now().UTC(),
Type: types.VoteTypePrecommit,
BlockID: types.BlockID{[]byte("fakehash"), types.PartSetHeader{}},
}
chainID := config.ChainID
chainID := config.ChainID()
err := privVal.SignVote(chainID, vote)
if err != nil {
panic(cmn.Fmt("Error signing vote: %v", err))

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 `json:"height"` // Height peer is at
Round int `json:"round"` // Round peer is at, -1 if unknown.
Step RoundStepType `json:"step"` // Step peer is at
StartTime time.Time `json:"start_time"` // Estimated start of round 0 at this height
Proposal bool `json:"proposal"` // True if peer has proposal for this round
ProposalBlockPartsHeader types.PartSetHeader `json:"proposal_block_parts_header"` //
ProposalBlockParts *cmn.BitArray `json:"proposal_block_parts"` //
ProposalPOLRound int `json:"proposal_pol_round"` // Proposal's POL round. -1 if none.
ProposalPOL *cmn.BitArray `json:"proposal_pol"` // nil until ProposalPOLMessage received.
Prevotes *cmn.BitArray `json:"prevotes"` // All votes peer has for this round
Precommits *cmn.BitArray `json:"precommits"` // All precommits peer has for this round
LastCommitRound int `json:"last_commit_round"` // Round of commit for last height. -1 if none.
LastCommit *cmn.BitArray `json:"last_commit"` // All commit precommits of commit for last height.
CatchupCommitRound int `json:"catchup_commit_round"` // Round that we have commit for. Not necessarily unique. -1 if none.
CatchupCommit *cmn.BitArray `json:"catchup_commit"` // 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)
}

View File

@@ -1,57 +0,0 @@
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 int // 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)
}

View File

@@ -0,0 +1,164 @@
package types
import (
"encoding/json"
"fmt"
"time"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
//-----------------------------------------------------------------------------
// RoundStepType enum type
// RoundStepType enumerates the state of the consensus state machine
type RoundStepType uint8 // These must be numeric, ordered.
// RoundStepType
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 `json:"height"` // Height we are working on
Round int `json:"round"`
Step RoundStepType `json:"step"`
StartTime time.Time `json:"start_time"`
CommitTime time.Time `json:"commit_time"` // Subjective time when +2/3 precommits for Block at Round were found
Validators *types.ValidatorSet `json:"validators"`
Proposal *types.Proposal `json:"proposal"`
ProposalBlock *types.Block `json:"proposal_block"`
ProposalBlockParts *types.PartSet `json:"proposal_block_parts"`
LockedRound int `json:"locked_round"`
LockedBlock *types.Block `json:"locked_block"`
LockedBlockParts *types.PartSet `json:"locked_block_parts"`
ValidRound int `json:"valid_round"` // Last known round with POL for non-nil valid block.
ValidBlock *types.Block `json:"valid_block"` // Last known block of POL mentioned above.
ValidBlockParts *types.PartSet `json:"valid_block_parts"` // Last known block parts of POL metnioned above.
Votes *HeightVoteSet `json:"votes"`
CommitRound int `json:"commit_round"` //
LastCommit *types.VoteSet `json:"last_commit"` // Last precommits at Height-1
LastValidators *types.ValidatorSet `json:"last_validators"`
}
// Compressed version of the RoundState for use in RPC
type RoundStateSimple struct {
HeightRoundStep string `json:"height/round/step"`
StartTime time.Time `json:"start_time"`
ProposalBlockHash cmn.HexBytes `json:"proposal_block_hash"`
LockedBlockHash cmn.HexBytes `json:"locked_block_hash"`
ValidBlockHash cmn.HexBytes `json:"valid_block_hash"`
Votes json.RawMessage `json:"height_vote_set"`
}
// Compress the RoundState to RoundStateSimple
func (rs *RoundState) RoundStateSimple() RoundStateSimple {
votesJSON, err := rs.Votes.MarshalJSON()
if err != nil {
panic(err)
}
return RoundStateSimple{
HeightRoundStep: fmt.Sprintf("%d/%d/%d", rs.Height, rs.Round, rs.Step),
StartTime: rs.StartTime,
ProposalBlockHash: rs.ProposalBlock.Hash(),
LockedBlockHash: rs.LockedBlock.Hash(),
ValidBlockHash: rs.ValidBlock.Hash(),
Votes: votesJSON,
}
}
// 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
rsCopy := *rs
edrs := types.EventDataRoundState{
Height: rs.Height,
Round: rs.Round,
Step: rs.Step.String(),
RoundState: &rsCopy,
}
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

@@ -0,0 +1,95 @@
package types
import (
"testing"
"time"
"github.com/tendermint/go-amino"
"github.com/tendermint/go-crypto"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
func BenchmarkRoundStateDeepCopy(b *testing.B) {
b.StopTimer()
// Random validators
nval, ntxs := 100, 100
vset, _ := types.RandValidatorSet(nval, 1)
precommits := make([]*types.Vote, nval)
blockID := types.BlockID{
Hash: cmn.RandBytes(20),
PartsHeader: types.PartSetHeader{
Hash: cmn.RandBytes(20),
},
}
sig := crypto.SignatureEd25519{}
for i := 0; i < nval; i++ {
precommits[i] = &types.Vote{
ValidatorAddress: types.Address(cmn.RandBytes(20)),
Timestamp: time.Now(),
BlockID: blockID,
Signature: sig,
}
}
txs := make([]types.Tx, ntxs)
for i := 0; i < ntxs; i++ {
txs[i] = cmn.RandBytes(100)
}
// Random block
block := &types.Block{
Header: &types.Header{
ChainID: cmn.RandStr(12),
Time: time.Now(),
LastBlockID: blockID,
LastCommitHash: cmn.RandBytes(20),
DataHash: cmn.RandBytes(20),
ValidatorsHash: cmn.RandBytes(20),
ConsensusHash: cmn.RandBytes(20),
AppHash: cmn.RandBytes(20),
LastResultsHash: cmn.RandBytes(20),
EvidenceHash: cmn.RandBytes(20),
},
Data: &types.Data{
Txs: txs,
},
Evidence: types.EvidenceData{},
LastCommit: &types.Commit{
BlockID: blockID,
Precommits: precommits,
},
}
parts := block.MakePartSet(4096)
// Random Proposal
proposal := &types.Proposal{
Timestamp: time.Now(),
BlockPartsHeader: types.PartSetHeader{
Hash: cmn.RandBytes(20),
},
POLBlockID: blockID,
Signature: sig,
}
// Random HeightVoteSet
// TODO: hvs :=
rs := &RoundState{
StartTime: time.Now(),
CommitTime: time.Now(),
Validators: vset,
Proposal: proposal,
ProposalBlock: block,
ProposalBlockParts: parts,
LockedBlock: block,
LockedBlockParts: parts,
ValidBlock: block,
ValidBlockParts: parts,
Votes: nil, // TODO
LastCommit: nil, // TODO
LastValidators: vset,
}
b.StartTimer()
for i := 0; i < b.N; i++ {
amino.DeepCopy(rs)
}
}

View File

@@ -1,126 +0,0 @@
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.
// It is Immutable when returned from ConsensusState.GetRoundState()
// TODO: Actually, only the top pointer is copied,
// so access to field pointers is still racey
type RoundState struct {
Height int // 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
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 {
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 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.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)
}

12
consensus/types/wire.go Normal file
View File

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

View File

@@ -1,104 +1,323 @@
package consensus
import (
"encoding/binary"
"fmt"
"hash/crc32"
"io"
"path/filepath"
"time"
wire "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 {
Write(WALMessage)
WriteSync(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 {
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) (*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 = *cmn.NewBaseService(nil, "WAL", wal)
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.WriteSync(EndHeightMessage{0})
}
_, err = wal.group.Start()
err = wal.group.Start()
return err
}
func (wal *WAL) OnStop() {
wal.BaseService.OnStop()
func (wal *baseWAL) OnStop() {
wal.group.Stop()
wal.group.Close()
}
// called in newStep and for each pass in receiveRoutine
func (wal *WAL) Save(wmsg WALMessage) {
// Write is called in newStep and for each receive on the
// peerMsgQueue and the timeoutTicker.
// NOTE: does not call fsync()
func (wal *baseWAL) Write(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 != "" {
return
// Write the wal message
if err := wal.enc.Encode(&TimedWALMessage{time.Now(), msg}); err != nil {
panic(cmn.Fmt("Error writing msg to consensus wal: %v \n\nMessage: %v", err, msg))
}
}
// WriteSync is called when we receive a msg from ourselves
// so that we write to disk before sending signed messages.
// NOTE: calls fsync()
func (wal *baseWAL) WriteSync(msg WALMessage) {
if wal == nil {
return
}
wal.Write(msg)
if err := wal.group.Flush(); err != nil {
panic(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 given 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
lastHeightFound := int64(-1)
// 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 {
// OPTIMISATION: no need to look for height in older files if we've seen h < height
if lastHeightFound > 0 && lastHeightFound < height {
gr.Close()
return nil, false, nil
}
// check next file
break
}
if options.IgnoreDataCorruptionErrors && IsDataCorruptionError(err) {
wal.Logger.Debug("Corrupted entry. Skipping...", "err", err)
// do nothing
continue
} else if err != nil {
gr.Close()
return nil, false, err
}
if m, ok := msg.Msg.(EndHeightMessage); ok {
lastHeightFound = m.Height
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
}
// Write the wal message
var wmsgBytes = wire.JSONBytes(TimedWALMessage{time.Now(), wmsg})
err := wal.group.WriteLine(string(wmsgBytes))
if err != nil {
cmn.PanicQ(cmn.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 {
cmn.PanicQ(cmn.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 != nil {
return nil, fmt.Errorf("failed to read length: %v", err)
}
length := binary.BigEndian.Uint32(b)
if length > maxMsgSizeBytes {
return nil, fmt.Errorf("length %d exceeded maximum possible value of %d bytes", length, maxMsgSizeBytes)
}
data := make([]byte, length)
_, err = dec.rd.Read(data)
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(cmn.Fmt("#ENDHEIGHT: %v", height))
type nilWAL struct{}
// 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))
}
func (nilWAL) Write(m WALMessage) {}
func (nilWAL) WriteSync(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
}

205
consensus/wal_generator.go Normal file
View File

@@ -0,0 +1,205 @@
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/privval"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
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 := privval.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)
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 := sm.MockMempool{}
evpool := sm.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.Write(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) Write(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) WriteSync(m WALMessage) {
w.Write(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)
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 (
"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:
- "26656-26657:26656-26657"
environment:
- ID=0
- LOG=$${LOG:-tendermint.log}
volumes:
- ./build:/tendermint:Z
networks:
localnet:
ipv4_address: 192.167.10.2
node1:
container_name: node1
image: "tendermint/localnode"
ports:
- "26659-26660:26656-26657"
environment:
- ID=1
- LOG=$${LOG:-tendermint.log}
volumes:
- ./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:
- "26661-26662:26656-26657"
volumes:
- ./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:
- "26663-26664:26656-26657"
volumes:
- ./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

1
docs/.python-version Normal file
View File

@@ -0,0 +1 @@
2.7.14

View File

@@ -12,6 +12,9 @@ BUILDDIR = _build
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
install:
@pip install -r requirements.txt
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new

View File

@@ -0,0 +1,17 @@
.toggle {
padding-bottom: 1em ;
}
.toggle .header {
display: block;
clear: both;
cursor: pointer;
}
.toggle .header:after {
content: " ▼";
}
.toggle .header.open:after {
content: " ▲";
}

10
docs/_static/custom_collapsible_code.js vendored Normal file
View File

@@ -0,0 +1,10 @@
let makeCodeBlocksCollapsible = function() {
$(".toggle > *").hide();
$(".toggle .header").show();
$(".toggle .header").click(function() {
$(this).parent().children().not(".header").toggle({"duration": 400});
$(this).parent().children(".header").toggleClass("open");
});
};
// we could use the }(); way if we would have access to jQuery in HEAD, i.e. we would need to force the theme
// to load jQuery before our custom scripts

20
docs/_templates/layout.html vendored Normal file
View File

@@ -0,0 +1,20 @@
{% extends "!layout.html" %}
{% set css_files = css_files + ["_static/custom_collapsible_code.css"] %}
# sadly, I didn't find a css style way to add custom JS to a list that is automagically added to head like CSS (above) #}
{% block extrahead %}
<script type="text/javascript" src="_static/custom_collapsible_code.js"></script>
{% endblock %}
{% block footer %}
<script type="text/javascript">
$(document).ready(function() {
// using this approach as we don't have access to the jQuery selectors
// when executing the function on load in HEAD
makeCodeBlocksCollapsible();
});
</script>
{% endblock %}

329
docs/abci-cli.md Normal file
View File

@@ -0,0 +1,329 @@
# Using ABCI-CLI
To facilitate testing and debugging of ABCI servers and simple apps, we
built a CLI, the `abci-cli`, for sending ABCI messages from the command
line.
## Install
Make sure you [have Go installed](https://golang.org/doc/install).
Next, install the `abci-cli` tool and example applications:
go get -u github.com/tendermint/abci/cmd/abci-cli
If this fails, you may need to use [dep](https://github.com/golang/dep)
to get vendored dependencies:
cd $GOPATH/src/github.com/tendermint/abci
make get_tools
make get_vendor_deps
make install
Now run `abci-cli` to see the list of commands:
Usage:
abci-cli [command]
Available Commands:
batch Run a batch of abci commands against an application
check_tx Validate a tx
commit Commit the application state and return the Merkle root hash
console Start an interactive abci console for multiple commands
counter ABCI demo example
deliver_tx Deliver a new tx to the application
kvstore ABCI demo example
echo Have the application echo a message
help Help about any command
info Get some info about the application
query Query the application state
set_option Set an options on the application
Flags:
--abci string socket or grpc (default "socket")
--address string address of application socket (default "tcp://127.0.0.1:26658")
-h, --help help for abci-cli
-v, --verbose print the command and results as if it were a console session
Use "abci-cli [command] --help" for more information about a command.
## KVStore - First Example
The `abci-cli` tool lets us send ABCI messages to our application, to
help build and debug them.
The most important messages are `deliver_tx`, `check_tx`, and `commit`,
but there are others for convenience, configuration, and information
purposes.
We'll start a kvstore application, which was installed at the same time
as `abci-cli` above. The kvstore just stores transactions in a merkle
tree.
Its code can be found
[here](https://github.com/tendermint/abci/blob/master/cmd/abci-cli/abci-cli.go)
and looks like:
func cmdKVStore(cmd *cobra.Command, args []string) error {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
// Create the application - in memory or persisted to disk
var app types.Application
if flagPersist == "" {
app = kvstore.NewKVStoreApplication()
} else {
app = kvstore.NewPersistentKVStoreApplication(flagPersist)
app.(*kvstore.PersistentKVStoreApplication).SetLogger(logger.With("module", "kvstore"))
}
// Start the listener
srv, err := server.NewServer(flagAddrD, flagAbci, app)
if err != nil {
return err
}
srv.SetLogger(logger.With("module", "abci-server"))
if err := srv.Start(); err != nil {
return err
}
// Wait forever
cmn.TrapSignal(func() {
// Cleanup
srv.Stop()
})
return nil
}
Start by running:
abci-cli kvstore
And in another terminal, run
abci-cli echo hello
abci-cli info
You'll see something like:
-> data: hello
-> data.hex: 68656C6C6F
and:
-> data: {"size":0}
-> data.hex: 7B2273697A65223A307D
An ABCI application must provide two things:
- a socket server
- a handler for ABCI messages
When we run the `abci-cli` tool we open a new connection to the
application's socket server, send the given ABCI message, and wait for a
response.
The server may be generic for a particular language, and we provide a
[reference implementation in
Golang](https://github.com/tendermint/abci/tree/master/server). See the
[list of other ABCI implementations](./ecosystem.html) for servers in
other languages.
The handler is specific to the application, and may be arbitrary, so
long as it is deterministic and conforms to the ABCI interface
specification.
So when we run `abci-cli info`, we open a new connection to the ABCI
server, which calls the `Info()` method on the application, which tells
us the number of transactions in our Merkle tree.
Now, since every command opens a new connection, we provide the
`abci-cli console` and `abci-cli batch` commands, to allow multiple ABCI
messages to be sent over a single connection.
Running `abci-cli console` should drop you in an interactive console for
speaking ABCI messages to your application.
Try running these commands:
> echo hello
-> code: OK
-> data: hello
-> data.hex: 0x68656C6C6F
> info
-> code: OK
-> data: {"size":0}
-> data.hex: 0x7B2273697A65223A307D
> commit
-> code: OK
-> data.hex: 0x0000000000000000
> deliver_tx "abc"
-> code: OK
> info
-> code: OK
-> data: {"size":1}
-> data.hex: 0x7B2273697A65223A317D
> commit
-> code: OK
-> data.hex: 0x0200000000000000
> query "abc"
-> code: OK
-> log: exists
-> height: 0
-> value: abc
-> value.hex: 616263
> deliver_tx "def=xyz"
-> code: OK
> commit
-> code: OK
-> data.hex: 0x0400000000000000
> query "def"
-> code: OK
-> log: exists
-> height: 0
-> value: xyz
-> value.hex: 78797A
Note that if we do `deliver_tx "abc"` it will store `(abc, abc)`, but if
we do `deliver_tx "abc=efg"` it will store `(abc, efg)`.
Similarly, you could put the commands in a file and run
`abci-cli --verbose batch < myfile`.
## Counter - Another Example
Now that we've got the hang of it, let's try another application, the
"counter" app.
Like the kvstore app, its code can be found
[here](https://github.com/tendermint/abci/blob/master/cmd/abci-cli/abci-cli.go)
and looks like:
func cmdCounter(cmd *cobra.Command, args []string) error {
app := counter.NewCounterApplication(flagSerial)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
// Start the listener
srv, err := server.NewServer(flagAddrC, flagAbci, app)
if err != nil {
return err
}
srv.SetLogger(logger.With("module", "abci-server"))
if err := srv.Start(); err != nil {
return err
}
// Wait forever
cmn.TrapSignal(func() {
// Cleanup
srv.Stop()
})
return nil
}
The counter app doesn't use a Merkle tree, it just counts how many times
we've sent a transaction, asked for a hash, or committed the state. The
result of `commit` is just the number of transactions sent.
This application has two modes: `serial=off` and `serial=on`.
When `serial=on`, transactions must be a big-endian encoded incrementing
integer, starting at 0.
If `serial=off`, there are no restrictions on transactions.
We can toggle the value of `serial` using the `set_option` ABCI message.
When `serial=on`, some transactions are invalid. In a live blockchain,
transactions collect in memory before they are committed into blocks. To
avoid wasting resources on invalid transactions, ABCI provides the
`check_tx` message, which application developers can use to accept or
reject transactions, before they are stored in memory or gossipped to
other peers.
In this instance of the counter app, `check_tx` only allows transactions
whose integer is greater than the last committed one.
Let's kill the console and the kvstore application, and start the
counter app:
abci-cli counter
In another window, start the `abci-cli console`:
> set_option serial on
-> code: OK
-> log: OK (SetOption doesn't return anything.)
> check_tx 0x00
-> code: OK
> check_tx 0xff
-> code: OK
> deliver_tx 0x00
-> code: OK
> check_tx 0x00
-> code: BadNonce
-> log: Invalid nonce. Expected >= 1, got 0
> deliver_tx 0x01
-> code: OK
> deliver_tx 0x04
-> code: BadNonce
-> log: Invalid nonce. Expected 2, got 4
> info
-> code: OK
-> data: {"hashes":0,"txs":2}
-> data.hex: 0x7B22686173686573223A302C22747873223A327D
This is a very simple application, but between `counter` and `kvstore`,
its easy to see how you can build out arbitrary application states on
top of the ABCI. [Hyperledger's
Burrow](https://github.com/hyperledger/burrow) also runs atop ABCI,
bringing with it Ethereum-like accounts, the Ethereum virtual-machine,
Monax's permissioning scheme, and native contracts extensions.
But the ultimate flexibility comes from being able to write the
application easily in any language.
We have implemented the counter in a number of languages [see the
example directory](https://github.com/tendermint/abci/tree/master/example).
To run the Node JS version, `cd` to `example/js` and run
node app.js
(you'll have to kill the other counter application process). In another
window, run the console and those previous ABCI commands. You should get
the same results as for the Go version.
## Bounties
Want to write the counter app in your favorite language?! We'd be happy
to add you to our [ecosystem](https://tendermint.com/ecosystem)! We're
also offering [bounties](https://hackerone.com/tendermint/) for
implementations in new languages!
The `abci-cli` is designed strictly for testing and debugging. In a real
deployment, the role of sending messages is taken by Tendermint, which
connects to the app using three separate connections, each with its own
pattern of messages.
For more information, see the [application developers
guide](./app-development.html). For examples of running an ABCI app with
Tendermint, see the [getting started guide](./getting-started.html).
Next is the ABCI specification.

View File

@@ -1,255 +0,0 @@
Using ABCI-CLI
==============
To facilitate testing and debugging of ABCI servers and simple apps, we
built a CLI, the ``abci-cli``, for sending ABCI messages from the
command line.
Install
-------
Make sure you `have Go installed <https://golang.org/doc/install>`__.
Next, install the ``abci-cli`` tool and example applications:
::
go get -u github.com/tendermint/abci/cmd/...
If this fails, you may need to use ``glide`` to get vendored
dependencies:
::
go get github.com/Masterminds/glide
cd $GOPATH/src/github.com/tendermint/abci
glide install
go install ./cmd/...
Now run ``abci-cli --help`` to see the list of commands:
::
COMMANDS:
batch Run a batch of ABCI commands against an application
console Start an interactive console for multiple commands
echo Have the application echo a message
info Get some info about the application
set_option Set an option on the application
deliver_tx Append a new tx to application
check_tx Validate a tx
commit Get application Merkle root hash
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--address "tcp://127.0.0.1:46658" address of application socket
--help, -h show help
--version, -v print the version
Dummy - First Example
---------------------
The ``abci-cli`` tool lets us send ABCI messages to our application, to
help build and debug them.
The most important messages are ``deliver_tx``, ``check_tx``, and
``commit``, but there are others for convenience, configuration, and
information purposes.
Let's start a dummy application, which was installed at the same time as
``abci-cli`` above. The dummy just stores transactions in a merkle tree:
::
dummy
In another terminal, run
::
abci-cli echo hello
abci-cli info
The application should echo ``hello`` and give you some information
about itself.
An ABCI application must provide two things:
- a socket server
- a handler for ABCI messages
When we run the ``abci-cli`` tool we open a new connection to the
application's socket server, send the given ABCI message, and wait for a
response.
The server may be generic for a particular language, and we provide a
`reference implementation in
Golang <https://github.com/tendermint/abci/tree/master/server>`__. See
the `list of other ABCI
implementations <https://tendermint.com/ecosystem>`__ for servers in
other languages.
The handler is specific to the application, and may be arbitrary, so
long as it is deterministic and conforms to the ABCI interface
specification.
So when we run ``abci-cli info``, we open a new connection to the ABCI
server, which calls the ``Info()`` method on the application, which
tells us the number of transactions in our Merkle tree.
Now, since every command opens a new connection, we provide the
``abci-cli console`` and ``abci-cli batch`` commands, to allow multiple
ABCI messages to be sent over a single connection.
Running ``abci-cli console`` should drop you in an interactive console
for speaking ABCI messages to your application.
Try running these commands:
::
> echo hello
-> data: hello
> info
-> data: {"size":0}
> commit
-> data: 0x
> deliver_tx "abc"
-> code: OK
> info
-> data: {"size":1}
> commit
-> data: 0x750502FC7E84BBD788ED589624F06CFA871845D1
> query "abc"
-> code: OK
-> data: {"index":0,"value":"abc","exists":true}
> deliver_tx "def=xyz"
-> code: OK
> commit
-> data: 0x76393B8A182E450286B0694C629ECB51B286EFD5
> query "def"
-> code: OK
-> data: {"index":1,"value":"xyz","exists":true}
Note that if we do ``deliver_tx "abc"`` it will store ``(abc, abc)``,
but if we do ``deliver_tx "abc=efg"`` it will store ``(abc, efg)``.
Similarly, you could put the commands in a file and run
``abci-cli --verbose batch < myfile``.
Counter - Another Example
-------------------------
Now that we've got the hang of it, let's try another application, the
"counter" app.
The counter app doesn't use a Merkle tree, it just counts how many times
we've sent a transaction, asked for a hash, or committed the state. The
result of ``commit`` is just the number of transactions sent.
This application has two modes: ``serial=off`` and ``serial=on``.
When ``serial=on``, transactions must be a big-endian encoded
incrementing integer, starting at 0.
If ``serial=off``, there are no restrictions on transactions.
We can toggle the value of ``serial`` using the ``set_option`` ABCI
message.
When ``serial=on``, some transactions are invalid. In a live blockchain,
transactions collect in memory before they are committed into blocks. To
avoid wasting resources on invalid transactions, ABCI provides the
``check_tx`` message, which application developers can use to accept or
reject transactions, before they are stored in memory or gossipped to
other peers.
In this instance of the counter app, ``check_tx`` only allows
transactions whose integer is greater than the last committed one.
Let's kill the console and the dummy application, and start the counter
app:
::
counter
In another window, start the ``abci-cli console``:
::
> set_option serial on
-> data: serial=on
> check_tx 0x00
-> code: OK
> check_tx 0xff
-> code: OK
> deliver_tx 0x00
-> code: OK
> check_tx 0x00
-> code: BadNonce
-> log: Invalid nonce. Expected >= 1, got 0
> deliver_tx 0x01
-> code: OK
> deliver_tx 0x04
-> code: BadNonce
-> log: Invalid nonce. Expected 2, got 4
> info
-> data: {"hashes":0,"txs":2}
This is a very simple application, but between ``counter`` and
``dummy``, its easy to see how you can build out arbitrary application
states on top of the ABCI. `Hyperledger's
Burrow <https://github.com/hyperledger/burrow>`__ also runs atop ABCI,
bringing with it Ethereum-like accounts, the Ethereum virtual-machine,
Monax's permissioning scheme, and native contracts extensions.
But the ultimate flexibility comes from being able to write the
application easily in any language.
We have implemented the counter in a number of languages (see the
example directory).
To run the Node JS version, ``cd`` to ``example/js`` and run
::
node app.js
(you'll have to kill the other counter application process). In another
window, run the console and those previous ABCI commands. You should get
the same results as for the Go version.
Bounties
--------
Want to write the counter app in your favorite language?! We'd be happy
to add you to our `ecosystem <https://tendermint.com/ecosystem>`__!
We're also offering `bounties <https://tendermint.com/bounties>`__ for
implementations in new languages!
The ``abci-cli`` is designed strictly for testing and debugging. In a
real deployment, the role of sending messages is taken by Tendermint,
which connects to the app using three separate connections, each with
its own pattern of messages.
For more information, see the `application developers
guide <./app-development.html>`__. For examples of running an ABCI
app with Tendermint, see the `getting started
guide <./getting-started.html>`__.

50
docs/app-architecture.md Normal file
View File

@@ -0,0 +1,50 @@
# Application Architecture Guide
Here we provide a brief guide on the recommended architecture of a
Tendermint blockchain application.
The following diagram provides a superb example:
<https://drive.google.com/open?id=1yR2XpRi9YCY9H9uMfcw8-RMJpvDyvjz9>
The end-user application here is the Cosmos Voyager, at the bottom left.
Voyager communicates with a REST API exposed by a local Light-Client
Daemon. The Light-Client Daemon is an application specific program that
communicates with Tendermint nodes and verifies Tendermint light-client
proofs through the Tendermint Core RPC. The Tendermint Core process
communicates with a local ABCI application, where the user query or
transaction is actually processed.
The ABCI application must be a deterministic result of the Tendermint
consensus - any external influence on the application state that didn't
come through Tendermint could cause a consensus failure. Thus *nothing*
should communicate with the application except Tendermint via ABCI.
If the application is written in Go, it can be compiled into the
Tendermint binary. Otherwise, it should use a unix socket to communicate
with Tendermint. If it's necessary to use TCP, extra care must be taken
to encrypt and authenticate the connection.
All reads from the app happen through the Tendermint `/abci_query`
endpoint. All writes to the app happen through the Tendermint
`/broadcast_tx_*` endpoints.
The Light-Client Daemon is what provides light clients (end users) with
nearly all the security of a full node. It formats and broadcasts
transactions, and verifies proofs of queries and transaction results.
Note that it need not be a daemon - the Light-Client logic could instead
be implemented in the same process as the end-user application.
Note for those ABCI applications with weaker security requirements, the
functionality of the Light-Client Daemon can be moved into the ABCI
application process itself. That said, exposing the application process
to anything besides Tendermint over ABCI requires extreme caution, as
all transactions, and possibly all queries, should still pass through
Tendermint.
See the following for more extensive documentation:
- [Interchain Standard for the Light-Client REST API](https://github.com/cosmos/cosmos-sdk/pull/1028)
- [Tendermint RPC Docs](https://tendermint.github.io/slate/)
- [Tendermint in Production](https://github.com/tendermint/tendermint/pull/1618)
- [Tendermint Basics](https://tendermint.readthedocs.io/en/master/using-tendermint.html)
- [ABCI spec](https://github.com/tendermint/abci/blob/develop/specification.md)

View File

@@ -1,125 +0,0 @@
Application Architecture Guide
==============================
Overview
--------
A blockchain application is more than the consensus engine and the
transaction logic (eg. smart contracts, business logic) as implemented
in the ABCI app. There are also (mobile, web, desktop) clients that will
need to connect and make use of the app. We will assume for now that you
have a well designed transactions and database model, but maybe this
will be the topic of another article. This article is more interested in
various ways of setting up the "plumbing" and connecting these pieces,
and demonstrating some evolving best practices.
Security
--------
A very important aspect when constructing a blockchain is security. The
consensus model can be DoSed (no consensus possible) by corrupting 1/3
of the validators and exploited (writing arbitrary blocks) by corrupting
2/3 of the validators. So, while the security is not that of the
"weakest link", you should take care that the "average link" is
sufficiently hardened.
One big attack surface on the validators is the communication between
the ABCI app and the tendermint core. This should be highly protected.
Ideally, the app and the core are running on the same machine, so no
external agent can target the communication channel. You can use unix
sockets (with permissions preventing access from other users), or even
compile the two apps into one binary if the ABCI app is also writen in
go. If you are unable to do that due to language support, then the ABCI
app should bind a TCP connection to localhost (127.0.0.1), which is less
efficient and secure, but still not reachable from outside. If you must
run the ABCI app and tendermint core on separate machines, make sure you
have a secure communication channel (ssh tunnel?)
Now assuming, you have linked together your app and the core securely,
you must also make sure no one can get on the machine it is hosted on.
At this point it is basic network security. Run on a secure operating
system (SELinux?). Limit who has access to the machine (user accounts,
but also where the physical machine is hosted). Turn off all services
except for ssh, which should only be accessible by some well-guarded
public/private key pairs (no password). And maybe even firewall off
access to the ports used by the validators, so only known validators can
connect.
There was also a suggestion on slack from @jhon about compiling
everything together with a unikernel for more security, such as
`Mirage <https://mirage.io>`__ or
`UNIK <https://github.com/emc-advanced-dev/unik>`__.
Connecting your client to the blockchain
----------------------------------------
Tendermint Core RPC
~~~~~~~~~~~~~~~~~~~
The concept is that the ABCI app is completely hidden from the outside
world and only communicated through a tested and secured `interface
exposed by the tendermint core <./specification/rpc.html>`__. This interface
exposes a lot of data on the block header and consensus process, which
is quite useful for externally verifying the system. It also includes
3(!) methods to broadcast a transaction (propose it for the blockchain,
and possibly await a response). And one method to query app-specific
data from the ABCI application.
Pros:
* Server code already written
* Access to block headers to validate merkle proofs (nice for light clients)
* Basic read/write functionality is supported
Cons:
* Limited interface to app. All queries must be serialized into
[]byte (less expressive than JSON over HTTP) and there is no way to push
data from ABCI app to the client (eg. notify me if account X receives a
transaction)
Custom ABCI server
~~~~~~~~~~~~~~~~~~
This was proposed by @wolfposd on slack and demonstrated by
`TMChat <https://github.com/wolfposd/TMChat>`__, a sample app. The
concept is to write a custom server for your app (with typical REST
API/websockets/etc for easy use by a mobile app). This custom server is
in the same binary as the ABCI app and data store, so can easily react
to complex events there that involve understanding the data format (send
a message if my balance drops below 500). All "writes" sent to this
server are proxied via websocket/JSON-RPC to tendermint core. When they
come back as deliver\_tx over ABCI, they will be written to the data
store. For "reads", we can do any queries we wish that are supported by
our architecture, using any web technology that is useful. The general
architecture is shown in the following diagram:
Pros: \* Separates application logic from blockchain logic \* Allows
much richer, more flexible client-facing API \* Allows pub-sub, watching
certain fields, etc.
Cons: \* Access to ABCI app can be dangerous (be VERY careful not to
write unless it comes from the validator node) \* No direct access to
the blockchain headers to verify tx \* You must write your own API (but
maybe that's a pro...)
Hybrid solutions
~~~~~~~~~~~~~~~~
Likely the least secure but most versatile. The client can access both
the tendermint node for all blockchain info, as well as a custom app
server, for complex queries and pub-sub on the abci app.
Pros: All from both above solutions
Cons: Even more complexity; even more attack vectors (less
security)
Scalability
-----------
Read replica using non-validating nodes? They could forward transactions
to the validators (fewer connections, more security), and locally allow
all queries in any of the above configurations. Thus, while
transaction-processing speed is limited by the speed of the abci app and
the number of validators, one should be able to scale our read
performance to quite an extent (until the replication process drains too
many resources from the validator nodes).

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