You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

559 lines
16 KiB

8 years ago
8 years ago
pubsub 2.0 (#3227) * green pubsub tests :OK: * get rid of clientToQueryMap * Subscribe and SubscribeUnbuffered * start adapting other pkgs to new pubsub * nope * rename MsgAndTags to Message * remove TagMap it does not bring any additional benefits * bring back EventSubscriber * fix test * fix data race in TestStartNextHeightCorrectly ``` Write at 0x00c0001c7418 by goroutine 796: github.com/tendermint/tendermint/consensus.TestStartNextHeightCorrectly() /go/src/github.com/tendermint/tendermint/consensus/state_test.go:1296 +0xad testing.tRunner() /usr/local/go/src/testing/testing.go:827 +0x162 Previous read at 0x00c0001c7418 by goroutine 858: github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote() /go/src/github.com/tendermint/tendermint/consensus/state.go:1631 +0x1366 github.com/tendermint/tendermint/consensus.(*ConsensusState).tryAddVote() /go/src/github.com/tendermint/tendermint/consensus/state.go:1476 +0x8f github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg() /go/src/github.com/tendermint/tendermint/consensus/state.go:667 +0xa1e github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine() /go/src/github.com/tendermint/tendermint/consensus/state.go:628 +0x794 Goroutine 796 (running) created at: testing.(*T).Run() /usr/local/go/src/testing/testing.go:878 +0x659 testing.runTests.func1() /usr/local/go/src/testing/testing.go:1119 +0xa8 testing.tRunner() /usr/local/go/src/testing/testing.go:827 +0x162 testing.runTests() /usr/local/go/src/testing/testing.go:1117 +0x4ee testing.(*M).Run() /usr/local/go/src/testing/testing.go:1034 +0x2ee main.main() _testmain.go:214 +0x332 Goroutine 858 (running) created at: github.com/tendermint/tendermint/consensus.(*ConsensusState).startRoutines() /go/src/github.com/tendermint/tendermint/consensus/state.go:334 +0x221 github.com/tendermint/tendermint/consensus.startTestRound() /go/src/github.com/tendermint/tendermint/consensus/common_test.go:122 +0x63 github.com/tendermint/tendermint/consensus.TestStateFullRound1() /go/src/github.com/tendermint/tendermint/consensus/state_test.go:255 +0x397 testing.tRunner() /usr/local/go/src/testing/testing.go:827 +0x162 ``` * fixes after my own review * fix formatting * wait 100ms before kicking a subscriber out + a test for indexer_service * fixes after my second review * no timeout * add changelog entries * fix merge conflicts * fix typos after Thane's review Co-Authored-By: melekes <anton.kalyaev@gmail.com> * reformat code * rewrite indexer service in the attempt to fix failing test https://github.com/tendermint/tendermint/pull/3227/#issuecomment-462316527 * Revert "rewrite indexer service in the attempt to fix failing test" This reverts commit 0d9107a098230de7138abb1c201877c246e89ed1. * another attempt to fix indexer * fixes after Ethan's review * use unbuffered channel when indexing transactions Refs https://github.com/tendermint/tendermint/pull/3227#discussion_r258786716 * add a comment for EventBus#SubscribeUnbuffered * format code
6 years ago
pubsub 2.0 (#3227) * green pubsub tests :OK: * get rid of clientToQueryMap * Subscribe and SubscribeUnbuffered * start adapting other pkgs to new pubsub * nope * rename MsgAndTags to Message * remove TagMap it does not bring any additional benefits * bring back EventSubscriber * fix test * fix data race in TestStartNextHeightCorrectly ``` Write at 0x00c0001c7418 by goroutine 796: github.com/tendermint/tendermint/consensus.TestStartNextHeightCorrectly() /go/src/github.com/tendermint/tendermint/consensus/state_test.go:1296 +0xad testing.tRunner() /usr/local/go/src/testing/testing.go:827 +0x162 Previous read at 0x00c0001c7418 by goroutine 858: github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote() /go/src/github.com/tendermint/tendermint/consensus/state.go:1631 +0x1366 github.com/tendermint/tendermint/consensus.(*ConsensusState).tryAddVote() /go/src/github.com/tendermint/tendermint/consensus/state.go:1476 +0x8f github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg() /go/src/github.com/tendermint/tendermint/consensus/state.go:667 +0xa1e github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine() /go/src/github.com/tendermint/tendermint/consensus/state.go:628 +0x794 Goroutine 796 (running) created at: testing.(*T).Run() /usr/local/go/src/testing/testing.go:878 +0x659 testing.runTests.func1() /usr/local/go/src/testing/testing.go:1119 +0xa8 testing.tRunner() /usr/local/go/src/testing/testing.go:827 +0x162 testing.runTests() /usr/local/go/src/testing/testing.go:1117 +0x4ee testing.(*M).Run() /usr/local/go/src/testing/testing.go:1034 +0x2ee main.main() _testmain.go:214 +0x332 Goroutine 858 (running) created at: github.com/tendermint/tendermint/consensus.(*ConsensusState).startRoutines() /go/src/github.com/tendermint/tendermint/consensus/state.go:334 +0x221 github.com/tendermint/tendermint/consensus.startTestRound() /go/src/github.com/tendermint/tendermint/consensus/common_test.go:122 +0x63 github.com/tendermint/tendermint/consensus.TestStateFullRound1() /go/src/github.com/tendermint/tendermint/consensus/state_test.go:255 +0x397 testing.tRunner() /usr/local/go/src/testing/testing.go:827 +0x162 ``` * fixes after my own review * fix formatting * wait 100ms before kicking a subscriber out + a test for indexer_service * fixes after my second review * no timeout * add changelog entries * fix merge conflicts * fix typos after Thane's review Co-Authored-By: melekes <anton.kalyaev@gmail.com> * reformat code * rewrite indexer service in the attempt to fix failing test https://github.com/tendermint/tendermint/pull/3227/#issuecomment-462316527 * Revert "rewrite indexer service in the attempt to fix failing test" This reverts commit 0d9107a098230de7138abb1c201877c246e89ed1. * another attempt to fix indexer * fixes after Ethan's review * use unbuffered channel when indexing transactions Refs https://github.com/tendermint/tendermint/pull/3227#discussion_r258786716 * add a comment for EventBus#SubscribeUnbuffered * format code
6 years ago
7 years ago
fix non deterministic test failures and race in privval socket (#3258) * node: decrease retry conn timeout in test Should fix #3256 The retry timeout was set to the default, which is the same as the accept timeout, so it's no wonder this would fail. Here we decrease the retry timeout so we can try many times before the accept timeout. * p2p: increase handshake timeout in test This fails sometimes, presumably because the handshake timeout is so low (only 50ms). So increase it to 1s. Should fix #3187 * privval: fix race with ping. closes #3237 Pings happen in a go-routine and can happen concurrently with other messages. Since we use a request/response protocol, we expect to send a request and get back the corresponding response. But with pings happening concurrently, this assumption could be violated. We were using a mutex, but only a RWMutex, where the RLock was being held for sending messages - this was to allow the underlying connection to be replaced if it fails. Turns out we actually need to use a full lock (not just a read lock) to prevent multiple requests from happening concurrently. * node: fix test name. DelayedStop -> DelayedStart * autofile: Wait() method In the TestWALTruncate in consensus/wal_test.go we remove the WAL directory at the end of the test. However the wal.Stop() does not properly wait for the autofile group to finish shutting down. Hence it was possible that the group's go-routine is still running when the cleanup happens, which causes a panic since the directory disappeared. Here we add a Wait() method to properly wait until the go-routine exits so we can safely clean up. This fixes #2852.
6 years ago
fix non deterministic test failures and race in privval socket (#3258) * node: decrease retry conn timeout in test Should fix #3256 The retry timeout was set to the default, which is the same as the accept timeout, so it's no wonder this would fail. Here we decrease the retry timeout so we can try many times before the accept timeout. * p2p: increase handshake timeout in test This fails sometimes, presumably because the handshake timeout is so low (only 50ms). So increase it to 1s. Should fix #3187 * privval: fix race with ping. closes #3237 Pings happen in a go-routine and can happen concurrently with other messages. Since we use a request/response protocol, we expect to send a request and get back the corresponding response. But with pings happening concurrently, this assumption could be violated. We were using a mutex, but only a RWMutex, where the RLock was being held for sending messages - this was to allow the underlying connection to be replaced if it fails. Turns out we actually need to use a full lock (not just a read lock) to prevent multiple requests from happening concurrently. * node: fix test name. DelayedStop -> DelayedStart * autofile: Wait() method In the TestWALTruncate in consensus/wal_test.go we remove the WAL directory at the end of the test. However the wal.Stop() does not properly wait for the autofile group to finish shutting down. Hence it was possible that the group's go-routine is still running when the cleanup happens, which causes a panic since the directory disappeared. Here we add a Wait() method to properly wait until the go-routine exits so we can safely clean up. This fixes #2852.
6 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
privval: refactor Remote signers (#3370) This PR is related to #3107 and a continuation of #3351 It is important to emphasise that in the privval original design, client/server and listening/dialing roles are inverted and do not follow a conventional interaction. Given two hosts A and B: Host A is listener/client Host B is dialer/server (contains the secret key) When A requires a signature, it needs to wait for B to dial in before it can issue a request. A only accepts a single connection and any failure leads to dropping the connection and waiting for B to reconnect. The original rationale behind this design was based on security. Host B only allows outbound connections to a list of whitelisted hosts. It is not possible to reach B unless B dials in. There are no listening/open ports in B. This PR results in the following changes: Refactors ping/heartbeat to avoid previously existing race conditions. Separates transport (dialer/listener) from signing (client/server) concerns to simplify workflow. Unifies and abstracts away the differences between unix and tcp sockets. A single signer endpoint implementation unifies connection handling code (read/write/close/connection obj) The signer request handler (server side) is customizable to increase testability. Updates and extends unit tests A high level overview of the classes is as follows: Transport (endpoints): The following classes take care of establishing a connection SignerDialerEndpoint SignerListeningEndpoint SignerEndpoint groups common functionality (read/write/timeouts/etc.) Signing (client/server): The following classes take care of exchanging request/responses SignerClient SignerServer This PR also closes #3601 Commits: * refactoring - work in progress * reworking unit tests * Encapsulating and fixing unit tests * Improve tests * Clean up * Fix/improve unit tests * clean up tests * Improving service endpoint * fixing unit test * fix linter issues * avoid invalid cache values (improve later?) * complete implementation * wip * improved connection loop * Improve reconnections + fixing unit tests * addressing comments * small formatting changes * clean up * Update node/node.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * check during initialization * dropping connecting when writing fails * removing break * use t.log instead * unifying and using cmn.GetFreePort() * review fixes * reordering and unifying drop connection * closing instead of signalling * refactored service loop * removed superfluous brackets * GetPubKey can return errors * Revert "GetPubKey can return errors" This reverts commit 68c06f19b4650389d7e5ab1659b318889028202c. * adding entry to changelog * Update CHANGELOG_PENDING.md Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * updating node.go * review fixes * fixes linter * fixing unit test * small fixes in comments * addressing review comments * addressing review comments 2 * reverting suggestion * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * do not expose brokenSignerDialerEndpoint * clean up logging * unifying methods shorten test time signer also drops * reenabling pings * improving testability + unit test * fixing go fmt + unit test * remove unused code * Addressing review comments * simplifying connection workflow * fix linter/go import issue * using base service quit * updating comment * Simplifying design + adjusting names * fixing linter issues * refactoring test harness + fixes * Addressing review comments * cleaning up * adding additional error check
5 years ago
privval: refactor Remote signers (#3370) This PR is related to #3107 and a continuation of #3351 It is important to emphasise that in the privval original design, client/server and listening/dialing roles are inverted and do not follow a conventional interaction. Given two hosts A and B: Host A is listener/client Host B is dialer/server (contains the secret key) When A requires a signature, it needs to wait for B to dial in before it can issue a request. A only accepts a single connection and any failure leads to dropping the connection and waiting for B to reconnect. The original rationale behind this design was based on security. Host B only allows outbound connections to a list of whitelisted hosts. It is not possible to reach B unless B dials in. There are no listening/open ports in B. This PR results in the following changes: Refactors ping/heartbeat to avoid previously existing race conditions. Separates transport (dialer/listener) from signing (client/server) concerns to simplify workflow. Unifies and abstracts away the differences between unix and tcp sockets. A single signer endpoint implementation unifies connection handling code (read/write/close/connection obj) The signer request handler (server side) is customizable to increase testability. Updates and extends unit tests A high level overview of the classes is as follows: Transport (endpoints): The following classes take care of establishing a connection SignerDialerEndpoint SignerListeningEndpoint SignerEndpoint groups common functionality (read/write/timeouts/etc.) Signing (client/server): The following classes take care of exchanging request/responses SignerClient SignerServer This PR also closes #3601 Commits: * refactoring - work in progress * reworking unit tests * Encapsulating and fixing unit tests * Improve tests * Clean up * Fix/improve unit tests * clean up tests * Improving service endpoint * fixing unit test * fix linter issues * avoid invalid cache values (improve later?) * complete implementation * wip * improved connection loop * Improve reconnections + fixing unit tests * addressing comments * small formatting changes * clean up * Update node/node.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * check during initialization * dropping connecting when writing fails * removing break * use t.log instead * unifying and using cmn.GetFreePort() * review fixes * reordering and unifying drop connection * closing instead of signalling * refactored service loop * removed superfluous brackets * GetPubKey can return errors * Revert "GetPubKey can return errors" This reverts commit 68c06f19b4650389d7e5ab1659b318889028202c. * adding entry to changelog * Update CHANGELOG_PENDING.md Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * updating node.go * review fixes * fixes linter * fixing unit test * small fixes in comments * addressing review comments * addressing review comments 2 * reverting suggestion * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * do not expose brokenSignerDialerEndpoint * clean up logging * unifying methods shorten test time signer also drops * reenabling pings * improving testability + unit test * fixing go fmt + unit test * remove unused code * Addressing review comments * simplifying connection workflow * fix linter/go import issue * using base service quit * updating comment * Simplifying design + adjusting names * fixing linter issues * refactoring test harness + fixes * Addressing review comments * cleaning up * adding additional error check
5 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
privval: refactor Remote signers (#3370) This PR is related to #3107 and a continuation of #3351 It is important to emphasise that in the privval original design, client/server and listening/dialing roles are inverted and do not follow a conventional interaction. Given two hosts A and B: Host A is listener/client Host B is dialer/server (contains the secret key) When A requires a signature, it needs to wait for B to dial in before it can issue a request. A only accepts a single connection and any failure leads to dropping the connection and waiting for B to reconnect. The original rationale behind this design was based on security. Host B only allows outbound connections to a list of whitelisted hosts. It is not possible to reach B unless B dials in. There are no listening/open ports in B. This PR results in the following changes: Refactors ping/heartbeat to avoid previously existing race conditions. Separates transport (dialer/listener) from signing (client/server) concerns to simplify workflow. Unifies and abstracts away the differences between unix and tcp sockets. A single signer endpoint implementation unifies connection handling code (read/write/close/connection obj) The signer request handler (server side) is customizable to increase testability. Updates and extends unit tests A high level overview of the classes is as follows: Transport (endpoints): The following classes take care of establishing a connection SignerDialerEndpoint SignerListeningEndpoint SignerEndpoint groups common functionality (read/write/timeouts/etc.) Signing (client/server): The following classes take care of exchanging request/responses SignerClient SignerServer This PR also closes #3601 Commits: * refactoring - work in progress * reworking unit tests * Encapsulating and fixing unit tests * Improve tests * Clean up * Fix/improve unit tests * clean up tests * Improving service endpoint * fixing unit test * fix linter issues * avoid invalid cache values (improve later?) * complete implementation * wip * improved connection loop * Improve reconnections + fixing unit tests * addressing comments * small formatting changes * clean up * Update node/node.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * check during initialization * dropping connecting when writing fails * removing break * use t.log instead * unifying and using cmn.GetFreePort() * review fixes * reordering and unifying drop connection * closing instead of signalling * refactored service loop * removed superfluous brackets * GetPubKey can return errors * Revert "GetPubKey can return errors" This reverts commit 68c06f19b4650389d7e5ab1659b318889028202c. * adding entry to changelog * Update CHANGELOG_PENDING.md Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * updating node.go * review fixes * fixes linter * fixing unit test * small fixes in comments * addressing review comments * addressing review comments 2 * reverting suggestion * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * do not expose brokenSignerDialerEndpoint * clean up logging * unifying methods shorten test time signer also drops * reenabling pings * improving testability + unit test * fixing go fmt + unit test * remove unused code * Addressing review comments * simplifying connection workflow * fix linter/go import issue * using base service quit * updating comment * Simplifying design + adjusting names * fixing linter issues * refactoring test harness + fixes * Addressing review comments * cleaning up * adding additional error check
5 years ago
Close and retry a RemoteSigner on err (#2923) * Close and recreate a RemoteSigner on err * Update changelog * Address Anton's comments / suggestions: - update changelog - restart TCPVal - shut down on `ErrUnexpectedResponse` * re-init remote signer client with fresh connection if Ping fails - add/update TODOs in secret connection - rename tcp.go -> tcp_client.go, same with ipc to clarify their purpose * account for `conn returned by waitConnection can be `nil` - also add TODO about RemoteSigner conn field * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn * Tests for retrying: IPC / TCP - shorter info log on success - set conn and use it in tests to close conn - add rwmutex for conn field in IPC * comments and doc.go * fix ipc tests. fixes #2677 * use constants for tests * cleanup some error statements * fixes #2784, race in tests * remove print statement * minor fixes from review * update comment on sts spec * cosmetics * p2p/conn: add failing tests * p2p/conn: make SecretConnection thread safe * changelog * IPCVal signer refactor - use a .reset() method - don't use embedded RemoteSignerClient - guard RemoteSignerClient with mutex - drop the .conn - expose Close() on RemoteSignerClient * apply IPCVal refactor to TCPVal * remove mtx from RemoteSignerClient * consolidate IPCVal and TCPVal, fixes #3104 - done in tcp_client.go - now called SocketVal - takes a listener in the constructor - make tcpListener and unixListener contain all the differences * delete ipc files * introduce unix and tcp dialer for RemoteSigner * rename files - drop tcp_ prefix - rename priv_validator.go to file.go * bring back listener options * fix node * fix priv_val_server * fix node test * minor cleanup and comments
6 years ago
privval: refactor Remote signers (#3370) This PR is related to #3107 and a continuation of #3351 It is important to emphasise that in the privval original design, client/server and listening/dialing roles are inverted and do not follow a conventional interaction. Given two hosts A and B: Host A is listener/client Host B is dialer/server (contains the secret key) When A requires a signature, it needs to wait for B to dial in before it can issue a request. A only accepts a single connection and any failure leads to dropping the connection and waiting for B to reconnect. The original rationale behind this design was based on security. Host B only allows outbound connections to a list of whitelisted hosts. It is not possible to reach B unless B dials in. There are no listening/open ports in B. This PR results in the following changes: Refactors ping/heartbeat to avoid previously existing race conditions. Separates transport (dialer/listener) from signing (client/server) concerns to simplify workflow. Unifies and abstracts away the differences between unix and tcp sockets. A single signer endpoint implementation unifies connection handling code (read/write/close/connection obj) The signer request handler (server side) is customizable to increase testability. Updates and extends unit tests A high level overview of the classes is as follows: Transport (endpoints): The following classes take care of establishing a connection SignerDialerEndpoint SignerListeningEndpoint SignerEndpoint groups common functionality (read/write/timeouts/etc.) Signing (client/server): The following classes take care of exchanging request/responses SignerClient SignerServer This PR also closes #3601 Commits: * refactoring - work in progress * reworking unit tests * Encapsulating and fixing unit tests * Improve tests * Clean up * Fix/improve unit tests * clean up tests * Improving service endpoint * fixing unit test * fix linter issues * avoid invalid cache values (improve later?) * complete implementation * wip * improved connection loop * Improve reconnections + fixing unit tests * addressing comments * small formatting changes * clean up * Update node/node.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * check during initialization * dropping connecting when writing fails * removing break * use t.log instead * unifying and using cmn.GetFreePort() * review fixes * reordering and unifying drop connection * closing instead of signalling * refactored service loop * removed superfluous brackets * GetPubKey can return errors * Revert "GetPubKey can return errors" This reverts commit 68c06f19b4650389d7e5ab1659b318889028202c. * adding entry to changelog * Update CHANGELOG_PENDING.md Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * updating node.go * review fixes * fixes linter * fixing unit test * small fixes in comments * addressing review comments * addressing review comments 2 * reverting suggestion * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * do not expose brokenSignerDialerEndpoint * clean up logging * unifying methods shorten test time signer also drops * reenabling pings * improving testability + unit test * fixing go fmt + unit test * remove unused code * Addressing review comments * simplifying connection workflow * fix linter/go import issue * using base service quit * updating comment * Simplifying design + adjusting names * fixing linter issues * refactoring test harness + fixes * Addressing review comments * cleaning up * adding additional error check
5 years ago
privval: refactor Remote signers (#3370) This PR is related to #3107 and a continuation of #3351 It is important to emphasise that in the privval original design, client/server and listening/dialing roles are inverted and do not follow a conventional interaction. Given two hosts A and B: Host A is listener/client Host B is dialer/server (contains the secret key) When A requires a signature, it needs to wait for B to dial in before it can issue a request. A only accepts a single connection and any failure leads to dropping the connection and waiting for B to reconnect. The original rationale behind this design was based on security. Host B only allows outbound connections to a list of whitelisted hosts. It is not possible to reach B unless B dials in. There are no listening/open ports in B. This PR results in the following changes: Refactors ping/heartbeat to avoid previously existing race conditions. Separates transport (dialer/listener) from signing (client/server) concerns to simplify workflow. Unifies and abstracts away the differences between unix and tcp sockets. A single signer endpoint implementation unifies connection handling code (read/write/close/connection obj) The signer request handler (server side) is customizable to increase testability. Updates and extends unit tests A high level overview of the classes is as follows: Transport (endpoints): The following classes take care of establishing a connection SignerDialerEndpoint SignerListeningEndpoint SignerEndpoint groups common functionality (read/write/timeouts/etc.) Signing (client/server): The following classes take care of exchanging request/responses SignerClient SignerServer This PR also closes #3601 Commits: * refactoring - work in progress * reworking unit tests * Encapsulating and fixing unit tests * Improve tests * Clean up * Fix/improve unit tests * clean up tests * Improving service endpoint * fixing unit test * fix linter issues * avoid invalid cache values (improve later?) * complete implementation * wip * improved connection loop * Improve reconnections + fixing unit tests * addressing comments * small formatting changes * clean up * Update node/node.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * check during initialization * dropping connecting when writing fails * removing break * use t.log instead * unifying and using cmn.GetFreePort() * review fixes * reordering and unifying drop connection * closing instead of signalling * refactored service loop * removed superfluous brackets * GetPubKey can return errors * Revert "GetPubKey can return errors" This reverts commit 68c06f19b4650389d7e5ab1659b318889028202c. * adding entry to changelog * Update CHANGELOG_PENDING.md Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_client.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_dialer_endpoint.go Co-Authored-By: jleni <juan.leni@zondax.ch> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: jleni <juan.leni@zondax.ch> * updating node.go * review fixes * fixes linter * fixing unit test * small fixes in comments * addressing review comments * addressing review comments 2 * reverting suggestion * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_client_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * Update privval/signer_listener_endpoint_test.go Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * do not expose brokenSignerDialerEndpoint * clean up logging * unifying methods shorten test time signer also drops * reenabling pings * improving testability + unit test * fixing go fmt + unit test * remove unused code * Addressing review comments * simplifying connection workflow * fix linter/go import issue * using base service quit * updating comment * Simplifying design + adjusting names * fixing linter issues * refactoring test harness + fixes * Addressing review comments * cleaning up * adding additional error check
5 years ago
fix non deterministic test failures and race in privval socket (#3258) * node: decrease retry conn timeout in test Should fix #3256 The retry timeout was set to the default, which is the same as the accept timeout, so it's no wonder this would fail. Here we decrease the retry timeout so we can try many times before the accept timeout. * p2p: increase handshake timeout in test This fails sometimes, presumably because the handshake timeout is so low (only 50ms). So increase it to 1s. Should fix #3187 * privval: fix race with ping. closes #3237 Pings happen in a go-routine and can happen concurrently with other messages. Since we use a request/response protocol, we expect to send a request and get back the corresponding response. But with pings happening concurrently, this assumption could be violated. We were using a mutex, but only a RWMutex, where the RLock was being held for sending messages - this was to allow the underlying connection to be replaced if it fails. Turns out we actually need to use a full lock (not just a read lock) to prevent multiple requests from happening concurrently. * node: fix test name. DelayedStop -> DelayedStart * autofile: Wait() method In the TestWALTruncate in consensus/wal_test.go we remove the WAL directory at the end of the test. However the wal.Stop() does not properly wait for the autofile group to finish shutting down. Hence it was possible that the group's go-routine is still running when the cleanup happens, which causes a panic since the directory disappeared. Here we add a Wait() method to properly wait until the go-routine exits so we can safely clean up. This fixes #2852.
6 years ago
fix non deterministic test failures and race in privval socket (#3258) * node: decrease retry conn timeout in test Should fix #3256 The retry timeout was set to the default, which is the same as the accept timeout, so it's no wonder this would fail. Here we decrease the retry timeout so we can try many times before the accept timeout. * p2p: increase handshake timeout in test This fails sometimes, presumably because the handshake timeout is so low (only 50ms). So increase it to 1s. Should fix #3187 * privval: fix race with ping. closes #3237 Pings happen in a go-routine and can happen concurrently with other messages. Since we use a request/response protocol, we expect to send a request and get back the corresponding response. But with pings happening concurrently, this assumption could be violated. We were using a mutex, but only a RWMutex, where the RLock was being held for sending messages - this was to allow the underlying connection to be replaced if it fails. Turns out we actually need to use a full lock (not just a read lock) to prevent multiple requests from happening concurrently. * node: fix test name. DelayedStop -> DelayedStart * autofile: Wait() method In the TestWALTruncate in consensus/wal_test.go we remove the WAL directory at the end of the test. However the wal.Stop() does not properly wait for the autofile group to finish shutting down. Hence it was possible that the group's go-routine is still running when the cleanup happens, which causes a panic since the directory disappeared. Here we add a Wait() method to properly wait until the go-routine exits so we can safely clean up. This fixes #2852.
6 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
mempool: move interface into mempool package (#3524) ## Description Refs #2659 Breaking changes in the mempool package: [mempool] #2659 Mempool now an interface old Mempool renamed to CListMempool NewMempool renamed to NewCListMempool Option renamed to CListOption MempoolReactor renamed to Reactor NewMempoolReactor renamed to NewReactor unexpose TxID method TxInfo.PeerID renamed to SenderID unexpose MempoolReactor.Mempool Breaking changes in the state package: [state] #2659 Mempool interface moved to mempool package MockMempool moved to top-level mock package and renamed to Mempool Non Breaking changes in the node package: [node] #2659 Add Mempool method, which allows you to access mempool ## Commits * move Mempool interface into mempool package Refs #2659 Breaking changes in the mempool package: - Mempool now an interface - old Mempool renamed to CListMempool Breaking changes to state package: - MockMempool moved to mempool/mock package and renamed to Mempool - Mempool interface moved to mempool package * assert CListMempool impl Mempool * gofmt code * rename MempoolReactor to Reactor - combine everything into one interface - rename TxInfo.PeerID to TxInfo.SenderID - unexpose MempoolReactor.Mempool * move mempool mock into top-level mock package * add a fixme TxsFront should not be a part of the Mempool interface because it leaks implementation details. Instead, we need to come up with general interface for querying the mempool so the MempoolReactor can fetch and broadcast txs to peers. * change node#Mempool to return interface * save commit = new reactor arch * Revert "save commit = new reactor arch" This reverts commit 1bfceacd9d65a720574683a7f22771e69af9af4d. * require CListMempool in mempool.Reactor * add two changelog entries * fixes after my own review * quote interfaces, structs and functions * fixes after Ismail's review * make node's mempool an interface * make InitWAL/CloseWAL methods a part of Mempool interface * fix merge conflicts * make node's mempool an interface
6 years ago
  1. package node
  2. import (
  3. "context"
  4. "fmt"
  5. "math"
  6. "net"
  7. "os"
  8. "syscall"
  9. "testing"
  10. "time"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. dbm "github.com/tendermint/tm-db"
  14. "github.com/tendermint/tendermint/abci/example/kvstore"
  15. cfg "github.com/tendermint/tendermint/config"
  16. "github.com/tendermint/tendermint/crypto"
  17. "github.com/tendermint/tendermint/crypto/ed25519"
  18. "github.com/tendermint/tendermint/crypto/tmhash"
  19. "github.com/tendermint/tendermint/evidence"
  20. "github.com/tendermint/tendermint/libs/log"
  21. tmrand "github.com/tendermint/tendermint/libs/rand"
  22. mempl "github.com/tendermint/tendermint/mempool"
  23. "github.com/tendermint/tendermint/p2p"
  24. p2pmock "github.com/tendermint/tendermint/p2p/mock"
  25. "github.com/tendermint/tendermint/privval"
  26. "github.com/tendermint/tendermint/proxy"
  27. sm "github.com/tendermint/tendermint/state"
  28. "github.com/tendermint/tendermint/store"
  29. "github.com/tendermint/tendermint/types"
  30. tmtime "github.com/tendermint/tendermint/types/time"
  31. )
  32. func TestNodeStartStop(t *testing.T) {
  33. config := cfg.ResetTestRoot("node_node_test")
  34. defer os.RemoveAll(config.RootDir)
  35. // create & start node
  36. n, err := DefaultNewNode(config, log.TestingLogger())
  37. require.NoError(t, err)
  38. err = n.Start()
  39. require.NoError(t, err)
  40. t.Logf("Started node %v", n.sw.NodeInfo())
  41. // wait for the node to produce a block
  42. blocksSub, err := n.EventBus().Subscribe(context.Background(), "node_test", types.EventQueryNewBlock)
  43. require.NoError(t, err)
  44. select {
  45. case <-blocksSub.Out():
  46. case <-blocksSub.Cancelled():
  47. t.Fatal("blocksSub was cancelled")
  48. case <-time.After(10 * time.Second):
  49. t.Fatal("timed out waiting for the node to produce a block")
  50. }
  51. // stop the node
  52. go func() {
  53. err = n.Stop()
  54. require.NoError(t, err)
  55. }()
  56. select {
  57. case <-n.Quit():
  58. case <-time.After(5 * time.Second):
  59. pid := os.Getpid()
  60. p, err := os.FindProcess(pid)
  61. if err != nil {
  62. panic(err)
  63. }
  64. err = p.Signal(syscall.SIGABRT)
  65. fmt.Println(err)
  66. t.Fatal("timed out waiting for shutdown")
  67. }
  68. }
  69. func TestSplitAndTrimEmpty(t *testing.T) {
  70. testCases := []struct {
  71. s string
  72. sep string
  73. cutset string
  74. expected []string
  75. }{
  76. {"a,b,c", ",", " ", []string{"a", "b", "c"}},
  77. {" a , b , c ", ",", " ", []string{"a", "b", "c"}},
  78. {" a, b, c ", ",", " ", []string{"a", "b", "c"}},
  79. {" a, ", ",", " ", []string{"a"}},
  80. {" ", ",", " ", []string{}},
  81. }
  82. for _, tc := range testCases {
  83. assert.Equal(t, tc.expected, splitAndTrimEmpty(tc.s, tc.sep, tc.cutset), "%s", tc.s)
  84. }
  85. }
  86. func TestNodeDelayedStart(t *testing.T) {
  87. config := cfg.ResetTestRoot("node_delayed_start_test")
  88. defer os.RemoveAll(config.RootDir)
  89. now := tmtime.Now()
  90. // create & start node
  91. n, err := DefaultNewNode(config, log.TestingLogger())
  92. n.GenesisDoc().GenesisTime = now.Add(2 * time.Second)
  93. require.NoError(t, err)
  94. err = n.Start()
  95. require.NoError(t, err)
  96. defer n.Stop() //nolint:errcheck // ignore for tests
  97. startTime := tmtime.Now()
  98. assert.Equal(t, true, startTime.After(n.GenesisDoc().GenesisTime))
  99. }
  100. func TestNodeSetAppVersion(t *testing.T) {
  101. config := cfg.ResetTestRoot("node_app_version_test")
  102. defer os.RemoveAll(config.RootDir)
  103. // create & start node
  104. n, err := DefaultNewNode(config, log.TestingLogger())
  105. require.NoError(t, err)
  106. // default config uses the kvstore app
  107. var appVersion uint64 = kvstore.ProtocolVersion
  108. // check version is set in state
  109. state, err := n.stateStore.Load()
  110. require.NoError(t, err)
  111. assert.Equal(t, state.Version.Consensus.App, appVersion)
  112. // check version is set in node info
  113. assert.Equal(t, n.nodeInfo.ProtocolVersion.App, appVersion)
  114. }
  115. func TestNodeSetPrivValTCP(t *testing.T) {
  116. addr := "tcp://" + testFreeAddr(t)
  117. config := cfg.ResetTestRoot("node_priv_val_tcp_test")
  118. defer os.RemoveAll(config.RootDir)
  119. config.BaseConfig.PrivValidatorListenAddr = addr
  120. dialer := privval.DialTCPFn(addr, 100*time.Millisecond, ed25519.GenPrivKey())
  121. dialerEndpoint := privval.NewSignerDialerEndpoint(
  122. log.TestingLogger(),
  123. dialer,
  124. )
  125. privval.SignerDialerEndpointTimeoutReadWrite(100 * time.Millisecond)(dialerEndpoint)
  126. signerServer := privval.NewSignerServer(
  127. dialerEndpoint,
  128. config.ChainID(),
  129. types.NewMockPV(),
  130. )
  131. go func() {
  132. err := signerServer.Start()
  133. if err != nil {
  134. panic(err)
  135. }
  136. }()
  137. defer signerServer.Stop() //nolint:errcheck // ignore for tests
  138. n, err := DefaultNewNode(config, log.TestingLogger())
  139. require.NoError(t, err)
  140. assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
  141. }
  142. // address without a protocol must result in error
  143. func TestPrivValidatorListenAddrNoProtocol(t *testing.T) {
  144. addrNoPrefix := testFreeAddr(t)
  145. config := cfg.ResetTestRoot("node_priv_val_tcp_test")
  146. defer os.RemoveAll(config.RootDir)
  147. config.BaseConfig.PrivValidatorListenAddr = addrNoPrefix
  148. _, err := DefaultNewNode(config, log.TestingLogger())
  149. assert.Error(t, err)
  150. }
  151. func TestNodeSetPrivValIPC(t *testing.T) {
  152. tmpfile := "/tmp/kms." + tmrand.Str(6) + ".sock"
  153. defer os.Remove(tmpfile) // clean up
  154. config := cfg.ResetTestRoot("node_priv_val_tcp_test")
  155. defer os.RemoveAll(config.RootDir)
  156. config.BaseConfig.PrivValidatorListenAddr = "unix://" + tmpfile
  157. dialer := privval.DialUnixFn(tmpfile)
  158. dialerEndpoint := privval.NewSignerDialerEndpoint(
  159. log.TestingLogger(),
  160. dialer,
  161. )
  162. privval.SignerDialerEndpointTimeoutReadWrite(100 * time.Millisecond)(dialerEndpoint)
  163. pvsc := privval.NewSignerServer(
  164. dialerEndpoint,
  165. config.ChainID(),
  166. types.NewMockPV(),
  167. )
  168. go func() {
  169. err := pvsc.Start()
  170. require.NoError(t, err)
  171. }()
  172. defer pvsc.Stop() //nolint:errcheck // ignore for tests
  173. n, err := DefaultNewNode(config, log.TestingLogger())
  174. require.NoError(t, err)
  175. assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
  176. }
  177. // testFreeAddr claims a free port so we don't block on listener being ready.
  178. func testFreeAddr(t *testing.T) string {
  179. ln, err := net.Listen("tcp", "127.0.0.1:0")
  180. require.NoError(t, err)
  181. defer ln.Close()
  182. return fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.TCPAddr).Port)
  183. }
  184. // create a proposal block using real and full
  185. // mempool and evidence pool and validate it.
  186. func TestCreateProposalBlock(t *testing.T) {
  187. config := cfg.ResetTestRoot("node_create_proposal")
  188. defer os.RemoveAll(config.RootDir)
  189. cc := proxy.NewLocalClientCreator(kvstore.NewApplication())
  190. proxyApp := proxy.NewAppConns(cc)
  191. err := proxyApp.Start()
  192. require.Nil(t, err)
  193. defer proxyApp.Stop() //nolint:errcheck // ignore for tests
  194. logger := log.TestingLogger()
  195. const height int64 = 1
  196. state, stateDB, privVals := state(1, height)
  197. stateStore := sm.NewStore(stateDB)
  198. maxBytes := 16384
  199. const partSize uint32 = 256
  200. maxEvidenceBytes := int64(maxBytes / 2)
  201. state.ConsensusParams.Block.MaxBytes = int64(maxBytes)
  202. state.ConsensusParams.Evidence.MaxBytes = maxEvidenceBytes
  203. proposerAddr, _ := state.Validators.GetByIndex(0)
  204. // Make Mempool
  205. mempool := mempl.NewCListMempool(
  206. config.Mempool,
  207. proxyApp.Mempool(),
  208. state.LastBlockHeight,
  209. mempl.WithMetrics(mempl.NopMetrics()),
  210. mempl.WithPreCheck(sm.TxPreCheck(state)),
  211. mempl.WithPostCheck(sm.TxPostCheck(state)),
  212. )
  213. mempool.SetLogger(logger)
  214. // Make EvidencePool
  215. evidenceDB := dbm.NewMemDB()
  216. blockStore := store.NewBlockStore(dbm.NewMemDB())
  217. evidencePool, err := evidence.NewPool(logger, evidenceDB, stateStore, blockStore)
  218. require.NoError(t, err)
  219. // fill the evidence pool with more evidence
  220. // than can fit in a block
  221. var currentBytes int64 = 0
  222. for currentBytes <= maxEvidenceBytes {
  223. ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(), privVals[0], "test-chain")
  224. currentBytes += int64(len(ev.Bytes()))
  225. evidencePool.ReportConflictingVotes(ev.VoteA, ev.VoteB)
  226. }
  227. evList, size := evidencePool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
  228. require.Less(t, size, state.ConsensusParams.Evidence.MaxBytes+1)
  229. evData := &types.EvidenceData{Evidence: evList}
  230. require.EqualValues(t, size, evData.ByteSize())
  231. // fill the mempool with more txs
  232. // than can fit in a block
  233. txLength := 100
  234. for i := 0; i <= maxBytes/txLength; i++ {
  235. tx := tmrand.Bytes(txLength)
  236. err := mempool.CheckTx(tx, nil, mempl.TxInfo{})
  237. assert.NoError(t, err)
  238. }
  239. blockExec := sm.NewBlockExecutor(
  240. stateStore,
  241. logger,
  242. proxyApp.Consensus(),
  243. mempool,
  244. evidencePool,
  245. )
  246. commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
  247. block, _ := blockExec.CreateProposalBlock(
  248. height,
  249. state, commit,
  250. proposerAddr,
  251. )
  252. // check that the part set does not exceed the maximum block size
  253. partSet := block.MakePartSet(partSize)
  254. assert.Less(t, partSet.ByteSize(), int64(maxBytes))
  255. partSetFromHeader := types.NewPartSetFromHeader(partSet.Header())
  256. for partSetFromHeader.Count() < partSetFromHeader.Total() {
  257. added, err := partSetFromHeader.AddPart(partSet.GetPart(int(partSetFromHeader.Count())))
  258. require.NoError(t, err)
  259. require.True(t, added)
  260. }
  261. assert.EqualValues(t, partSetFromHeader.ByteSize(), partSet.ByteSize())
  262. err = blockExec.ValidateBlock(state, block)
  263. assert.NoError(t, err)
  264. }
  265. func TestMaxTxsProposalBlockSize(t *testing.T) {
  266. config := cfg.ResetTestRoot("node_create_proposal")
  267. defer os.RemoveAll(config.RootDir)
  268. cc := proxy.NewLocalClientCreator(kvstore.NewApplication())
  269. proxyApp := proxy.NewAppConns(cc)
  270. err := proxyApp.Start()
  271. require.Nil(t, err)
  272. defer proxyApp.Stop() //nolint:errcheck // ignore for tests
  273. logger := log.TestingLogger()
  274. const height int64 = 1
  275. state, stateDB, _ := state(1, height)
  276. stateStore := sm.NewStore(stateDB)
  277. const maxBytes int64 = 16384
  278. const partSize uint32 = 256
  279. state.ConsensusParams.Block.MaxBytes = maxBytes
  280. proposerAddr, _ := state.Validators.GetByIndex(0)
  281. // Make Mempool
  282. mempool := mempl.NewCListMempool(
  283. config.Mempool,
  284. proxyApp.Mempool(),
  285. state.LastBlockHeight,
  286. mempl.WithMetrics(mempl.NopMetrics()),
  287. mempl.WithPreCheck(sm.TxPreCheck(state)),
  288. mempl.WithPostCheck(sm.TxPostCheck(state)),
  289. )
  290. mempool.SetLogger(logger)
  291. // fill the mempool with one txs just below the maximum size
  292. txLength := int(types.MaxDataBytesNoEvidence(maxBytes, 1))
  293. tx := tmrand.Bytes(txLength - 4) // to account for the varint
  294. err = mempool.CheckTx(tx, nil, mempl.TxInfo{})
  295. assert.NoError(t, err)
  296. blockExec := sm.NewBlockExecutor(
  297. stateStore,
  298. logger,
  299. proxyApp.Consensus(),
  300. mempool,
  301. sm.EmptyEvidencePool{},
  302. )
  303. commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
  304. block, _ := blockExec.CreateProposalBlock(
  305. height,
  306. state, commit,
  307. proposerAddr,
  308. )
  309. pb, err := block.ToProto()
  310. require.NoError(t, err)
  311. assert.Less(t, int64(pb.Size()), maxBytes)
  312. // check that the part set does not exceed the maximum block size
  313. partSet := block.MakePartSet(partSize)
  314. assert.EqualValues(t, partSet.ByteSize(), int64(pb.Size()))
  315. }
  316. func TestMaxProposalBlockSize(t *testing.T) {
  317. config := cfg.ResetTestRoot("node_create_proposal")
  318. defer os.RemoveAll(config.RootDir)
  319. cc := proxy.NewLocalClientCreator(kvstore.NewApplication())
  320. proxyApp := proxy.NewAppConns(cc)
  321. err := proxyApp.Start()
  322. require.Nil(t, err)
  323. defer proxyApp.Stop() //nolint:errcheck // ignore for tests
  324. logger := log.TestingLogger()
  325. state, stateDB, _ := state(types.MaxVotesCount, int64(1))
  326. stateStore := sm.NewStore(stateDB)
  327. const maxBytes int64 = 1024 * 1024 * 2
  328. state.ConsensusParams.Block.MaxBytes = maxBytes
  329. proposerAddr, _ := state.Validators.GetByIndex(0)
  330. // Make Mempool
  331. mempool := mempl.NewCListMempool(
  332. config.Mempool,
  333. proxyApp.Mempool(),
  334. state.LastBlockHeight,
  335. mempl.WithMetrics(mempl.NopMetrics()),
  336. mempl.WithPreCheck(sm.TxPreCheck(state)),
  337. mempl.WithPostCheck(sm.TxPostCheck(state)),
  338. )
  339. mempool.SetLogger(logger)
  340. // fill the mempool with one txs just below the maximum size
  341. txLength := int(types.MaxDataBytesNoEvidence(maxBytes, types.MaxVotesCount))
  342. tx := tmrand.Bytes(txLength - 6) // to account for the varint
  343. err = mempool.CheckTx(tx, nil, mempl.TxInfo{})
  344. assert.NoError(t, err)
  345. // now produce more txs than what a normal block can hold with 10 smaller txs
  346. // At the end of the test, only the single big tx should be added
  347. for i := 0; i < 10; i++ {
  348. tx := tmrand.Bytes(10)
  349. err = mempool.CheckTx(tx, nil, mempl.TxInfo{})
  350. assert.NoError(t, err)
  351. }
  352. blockExec := sm.NewBlockExecutor(
  353. stateStore,
  354. logger,
  355. proxyApp.Consensus(),
  356. mempool,
  357. sm.EmptyEvidencePool{},
  358. )
  359. blockID := types.BlockID{
  360. Hash: tmhash.Sum([]byte("blockID_hash")),
  361. PartSetHeader: types.PartSetHeader{
  362. Total: math.MaxInt32,
  363. Hash: tmhash.Sum([]byte("blockID_part_set_header_hash")),
  364. },
  365. }
  366. timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC)
  367. // change state in order to produce the largest accepted header
  368. state.LastBlockID = blockID
  369. state.LastBlockHeight = math.MaxInt64 - 1
  370. state.LastBlockTime = timestamp
  371. state.LastResultsHash = tmhash.Sum([]byte("last_results_hash"))
  372. state.AppHash = tmhash.Sum([]byte("app_hash"))
  373. state.Version.Consensus.Block = math.MaxInt64
  374. state.Version.Consensus.App = math.MaxInt64
  375. maxChainID := ""
  376. for i := 0; i < types.MaxChainIDLen; i++ {
  377. maxChainID += "𠜎"
  378. }
  379. state.ChainID = maxChainID
  380. cs := types.CommitSig{
  381. BlockIDFlag: types.BlockIDFlagNil,
  382. ValidatorAddress: crypto.AddressHash([]byte("validator_address")),
  383. Timestamp: timestamp,
  384. Signature: crypto.CRandBytes(types.MaxSignatureSize),
  385. }
  386. commit := &types.Commit{
  387. Height: math.MaxInt64,
  388. Round: math.MaxInt32,
  389. BlockID: blockID,
  390. }
  391. // add maximum amount of signatures to a single commit
  392. for i := 0; i < types.MaxVotesCount; i++ {
  393. commit.Signatures = append(commit.Signatures, cs)
  394. }
  395. block, partSet := blockExec.CreateProposalBlock(
  396. math.MaxInt64,
  397. state, commit,
  398. proposerAddr,
  399. )
  400. // this ensures that the header is at max size
  401. block.Header.Time = timestamp
  402. pb, err := block.ToProto()
  403. require.NoError(t, err)
  404. // require that the header and commit be the max possible size
  405. require.Equal(t, int64(pb.Header.Size()), types.MaxHeaderBytes)
  406. require.Equal(t, int64(pb.LastCommit.Size()), types.MaxCommitBytes(types.MaxVotesCount))
  407. // make sure that the block is less than the max possible size
  408. assert.Equal(t, int64(pb.Size()), maxBytes)
  409. // because of the proto overhead we expect the part set bytes to be equal or
  410. // less than the pb block size
  411. assert.LessOrEqual(t, partSet.ByteSize(), int64(pb.Size()))
  412. }
  413. func TestNodeNewNodeCustomReactors(t *testing.T) {
  414. config := cfg.ResetTestRoot("node_new_node_custom_reactors_test")
  415. defer os.RemoveAll(config.RootDir)
  416. cr := p2pmock.NewReactor()
  417. customBlockchainReactor := p2pmock.NewReactor()
  418. nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
  419. require.NoError(t, err)
  420. pval, err := privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
  421. require.NoError(t, err)
  422. n, err := NewNode(config,
  423. pval,
  424. nodeKey,
  425. proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
  426. DefaultGenesisDocProviderFunc(config),
  427. DefaultDBProvider,
  428. DefaultMetricsProvider(config.Instrumentation),
  429. log.TestingLogger(),
  430. CustomReactors(map[string]p2p.Reactor{"FOO": cr, "BLOCKCHAIN": customBlockchainReactor}),
  431. )
  432. require.NoError(t, err)
  433. err = n.Start()
  434. require.NoError(t, err)
  435. defer n.Stop() //nolint:errcheck // ignore for tests
  436. assert.True(t, cr.IsRunning())
  437. assert.Equal(t, cr, n.Switch().Reactor("FOO"))
  438. assert.True(t, customBlockchainReactor.IsRunning())
  439. assert.Equal(t, customBlockchainReactor, n.Switch().Reactor("BLOCKCHAIN"))
  440. }
  441. func state(nVals int, height int64) (sm.State, dbm.DB, []types.PrivValidator) {
  442. privVals := make([]types.PrivValidator, nVals)
  443. vals := make([]types.GenesisValidator, nVals)
  444. for i := 0; i < nVals; i++ {
  445. privVal := types.NewMockPV()
  446. privVals[i] = privVal
  447. vals[i] = types.GenesisValidator{
  448. Address: privVal.PrivKey.PubKey().Address(),
  449. PubKey: privVal.PrivKey.PubKey(),
  450. Power: 1000,
  451. Name: fmt.Sprintf("test%d", i),
  452. }
  453. }
  454. s, _ := sm.MakeGenesisState(&types.GenesisDoc{
  455. ChainID: "test-chain",
  456. Validators: vals,
  457. AppHash: nil,
  458. })
  459. // save validators to db for 2 heights
  460. stateDB := dbm.NewMemDB()
  461. stateStore := sm.NewStore(stateDB)
  462. if err := stateStore.Save(s); err != nil {
  463. panic(err)
  464. }
  465. for i := 1; i < int(height); i++ {
  466. s.LastBlockHeight++
  467. s.LastValidators = s.Validators.Copy()
  468. if err := stateStore.Save(s); err != nil {
  469. panic(err)
  470. }
  471. }
  472. return s, stateDB, privVals
  473. }