Commit Graph

204 Commits

Author SHA1 Message Date
Henry de Valence 8e709bfa88 network: don't fail on unsolicited messages
These messages might be unsolicited, or they might be a response to a
request we already canceled.  So don't fail the whole connection, just
drop the message and move on.
2020-10-26 12:05:35 -07:00
Henry de Valence 13daefa729 network: handle request cancellation in Connection
We handle request cancellation in two places: before we transition into
the AwaitingResponse state, and while we are in AwaitingResponse.  We
need both places, or else if we started processing a request, we
wouldn't process the cancellation until the timeout elapsed.

The first is a check that the oneshot is not already canceled.

For the second, we wait on a cancellation, either from a timeout or from
the tx channel closing.
2020-10-26 12:05:35 -07:00
teor 1e97691fc8 Fix some "needless lifetime" clippy lints
These lints seem to be new in clippy nightly.
2020-10-12 08:54:23 +10:00
Henry de Valence b72c249b96 network: add a metric+warning when shedding load 2020-09-21 09:26:39 -07:00
Henry de Valence 4df5632752 network: handle Message::NotFound as a response
This cleans up the response processing logic a little bit along the way,
but the overall division of responsibility should be better documented
in a future commit.
2020-09-20 10:21:18 -07:00
Henry de Valence 64905563d1 network: remove glob import in message-handling
This clarifies which parts are the handler state and which parts are the
incoming message.
2020-09-20 10:21:18 -07:00
Henry de Valence 9c021025a7 network: fill in remaining request/response pairs 2020-09-20 10:21:18 -07:00
Henry de Valence b289cb9164 network: clean up GetHeaders, GetBlocks modeling 2020-09-20 10:21:18 -07:00
Henry de Valence 3c993f33b1 network: add PeerError::WrongMessage
This lets us distinguish between cases where the message was unsupported
(e.g., BIP11 messages), and cases where the message was uninterpretable
in context (e.g., unsolicited messages).
2020-09-20 10:21:18 -07:00
Henry de Valence 430176dd0d network: clean up message-as-request translation 2020-09-20 10:21:18 -07:00
Henry de Valence 1d3892e1dc network: rename alias to BoxError
This is shorter and consistent with Tower (which is why we use it in the
first place).
2020-09-18 18:34:25 -07:00
teor 1f7af0a779 Update the inv message processing comment
Cleanup after PR #1028.
2020-09-09 15:29:38 -07:00
Jane Lusby 1b17691dda improve logging 2020-09-08 12:37:34 -07:00
Jane Lusby 81a3ad3a0d filter inventory advertisements correctly 2020-09-08 12:37:34 -07:00
Henry de Valence 3f150eb16e
network: implement transaction request handling. (#1016)
This commit makes several related changes to the network code:

- adds a `TransactionsByHash(HashSet<transaction::Hash>)` request and
  `Transactions(Vec<Arc<Transaction>>)` response pair that allows
  fetching transactions from a remote peer;

- adds a `PushTransaction(Arc<Transaction>)` request that pushes an
  unsolicited transaction to a remote peer;

- adds an `AdvertiseTransactions(HashSet<transaction::Hash>)` request
  that advertises transactions by hash to a remote peer;

- adds an `AdvertiseBlock(block::Hash)` request that advertises a block
  by hash to a remote peer;

Then, it modifies the connection state machine so that outbound
requests to remote peers are handled properly:

- `TransactionsByHash` generates a `getdata` message and collects the
  results, like the existing `BlocksByHash` request.

- `PushTransaction` generates a `tx` message, and returns `Nil` immediately.

- `AdvertiseTransactions` and `AdvertiseBlock` generate an `inv`
  message, and return `Nil` immediately.

Next, it modifies the connection state machine so that messages
from remote peers generate requests to the inbound service:

- `getdata` messages generate `BlocksByHash` or `TransactionsByHash`
  requests, depending on the content of the message;

- `tx` messages generate `PushTransaction` requests;

- `inv` messages generate `AdvertiseBlock` or `AdvertiseTransactions`
  requests.

Finally, it refactors the request routing logic for the peer set to
handle advertisement messages, providing three routing methods:

- `route_p2c`, which uses p2c as normal (default);
- `route_inv`, which uses the inventory registry and falls back to p2c
  (used for `BlocksByHash` or `TransactionsByHash`);
- `route_all`, which broadcasts a request to all ready peers (used for
  `AdvertiseBlock` and `AdvertiseTransactions`).
2020-09-08 10:16:29 -07:00
teor b5c653ed93
Use ok_or for constants, rather than a redudant closure
* Use ok_or for constants in zebra-network
* Use ok_or for constants in zebra-consensus
2020-09-02 14:26:26 +10:00
Jane Lusby 88557ddd0a address more comments 2020-09-01 21:01:38 -04:00
Jane Lusby d933abeebf fix typo 2020-09-01 21:01:38 -04:00
Jane Lusby 96c8809348
Implement Inventory Tracking RFC (#963)
* Add .cargo to the gitignore file

* Implement Inventory Tracking RFC

* checkpoint

* wire together the inventory registry

* add comment documenting condition

* make inventory registry optional
2020-09-01 14:28:54 -07:00
Henry de Valence f91b91b6d8 network: clarify comment on Default for handshake::Builder
Co-authored-by: Jane Lusby <jlusby42@gmail.com>
2020-09-01 13:56:00 -07:00
Henry de Valence fddba7a336 network: remove handshake::Builder::with_addr
Use the listen_addr field already specified in the config.

Also, derive Clone for Handshake<S>.

Co-authored-by: Jane Lusby <jane@zfnd.org>
2020-09-01 13:56:00 -07:00
Henry de Valence a5b6f39850 network: don't leak our exact time skew in handshakes. 2020-09-01 13:56:00 -07:00
Henry de Valence 60a0b8c382 network: change Handshake::new to a Builder.
This allows more detailed control over the handshake parameters.
2020-09-01 13:56:00 -07:00
Henry de Valence 103b663c40 chain: rename BlockHeight to block::Height 2020-08-17 11:46:34 -07:00
Henry de Valence 61dea90e2f chain: rename BlockHeaderHash to block::Hash
This is the first in a sequence of changes that change the block:: items
to not include Block as a prefix in their name, in accordance with the
Rust API guidelines.
2020-08-17 11:46:34 -07:00
Henry de Valence dad6340cd3 chain: move BlockHeight into block 2020-08-17 11:46:34 -07:00
Alfredo Garcia b41e33e066
Bytes read and bytes written metrics (#901)
* add bytes read and written metrics

* Apply suggestions from code review

Co-authored-by: Jane Lusby <jlusby42@gmail.com>

* store address as string

* Apply suggestions from code review

Co-authored-by: Henry de Valence <hdevalence@hdevalence.ca>

* change addr to label

Co-authored-by: Henry de Valence <hdevalence@hdevalence.ca>

* remove newline

Co-authored-by: Jane Lusby <jlusby42@gmail.com>
Co-authored-by: Henry de Valence <hdevalence@hdevalence.ca>
2020-08-14 15:50:26 -07:00
Henry de Valence 3d46ab746a
Clean up options in network config section. (#839)
Closes #536.

This removes:

- the user-agent (we can add a mechanism to specify extra BIP14 components later, if any users ask us for that feature);
- the EWMA parameters (these were put in the config just to avoid making a choice);
- the peer connection timeout (we can change the default value if anyone ever has a problem with it);
- the peer set request buffer size (setting this too low can make the application deadlock);

The new peer interval is left in.
2020-08-06 11:29:00 -07:00
teor da09965a5f feature: Get the current minimum protocol version 2020-07-23 15:52:18 +10:00
teor c9ee85c3b5 feature: Add network upgrade activation heights 2020-07-23 15:52:18 +10:00
Henry de Valence 4a41c9254d network: avoid panic when shutting down cleanly.
When the connection sees the client_rx channel close it knows it will never get
any more requests, and it should terminate.  But instead of terminating, it
errored itself, and the method to error itself tries to pull all the
outstanding client requests from the channel in order to fail them before it
shuts down.  This results in reading from a closed channel, causing a panic.
Instead we return cleanly rather than failing (since we know there are no
outstanding requests, as the channel is closed).
2020-07-22 18:04:45 +10:00
Henry de Valence 0dc2d92ad8 network: ensure dropping a Client closes the connection.
This fixes a bug introduced when we added heartbeat support.  Recall that we
handle the Bitcoin connection state machine on a per-peer basis.  Each
connection has a task created from the `Connection` struct, and a `Client:
tower::Service` "frontend" that passes requests to it via a channel.  In the
`Connection` event loop, the connection checks whether the request channel has
been closed, indicating no further requests from the `Client`, in which case it
shuts itself down and cleans up resources.  This occurs when all of the senders
have been dropped.

However, this behavior broke when we introduced heartbeat support, because we
spawned an additional task to send heartbeat messages along the request
channel.  This meant that instead of having a single sender, dropped by the
`Client`, we have two senders, the `Client` and the "shadow client" task that
generates heartbeat messages.  This means that when the `Client` is dropped, we
still have a live sender and the connection is not closed.  To fix this, the
`Client` now uses a `oneshot` to shut down its corresponding heartbeat task.
This closes all senders.
2020-07-21 15:43:31 -07:00
teor b0cd920fad feature: Use the Heartwood protocol version in zebra-network 2020-07-21 10:46:07 -07:00
teor ab6d1f5ec8
fix: Use the default Zcash port in version messages (#661)
We don't provide our address yet, so the port should be ignored.

But let's use the correct port, to avoid carrying this bug forward into
working code.
2020-07-15 11:43:28 -07:00
Henry de Valence fcd2f43f39 network: add warning to connection handling code. 2020-07-09 11:15:06 -07:00
Henry de Valence 217c25ef07 network: propagate tracing Spans through peer connection 2020-07-09 11:15:06 -07:00
Deirdre Connolly 05316dee21 Listen on 0.0.0.0, not 127.0.0.1
Turns out when your node faces the internet directly, it has to listen
to those addresses directly.
2020-06-19 03:46:09 -04:00
Jane Lusby df18ac72c5 fix sharedpeererror to propagate tracing context 2020-06-17 14:38:26 -07:00
Jane Lusby 4b9e4520ce
cleanup API for arc based error type (#469)
Co-authored-by: Jane Lusby <jane@zfnd.org>
2020-06-12 11:29:42 -07:00
Jane Lusby 9bcda0f9c7 Wrap Blocks in Arc throughout codebase 2020-06-05 00:36:55 -04:00
Jane Lusby 4a2d2a359c
add cargo fmt to ci (#403)
* add cargo fmt to ci

* rebase on main

* switch to stable

Co-authored-by: Jane Lusby <jane@zfnd.org>
2020-05-27 19:12:25 -07:00
Jane Lusby 8276bed400 reinstate reject error variant 2020-05-27 15:42:29 -04:00
Jane Lusby b6b35364f3 cleanup warnings throughout codebase 2020-05-27 15:42:29 -04:00
George Tankersley df79fa75e0
Implement minimal version handshaking (#295)
Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
Co-authored-by: Henry de Valence <hdevalence@hdevalence.ca>
2020-04-13 18:33:15 -04:00
Deirdre Connolly 8c0b00109f Remove PeerError::DeadServer, unused, unneeded
Resolves #251
2020-03-12 16:23:08 -04:00
Henry de Valence 3ed75cb626 Tweak peer set metrics.
- Add a total peers metric to prevent races between measurements of
  ready/unready peers (which can cause the sum to be wrong).
- Add an outbound request counter.
2020-02-21 06:48:25 -05:00
Henry de Valence 80e7ee6dae Add metrics for inbound and outbound messages. 2020-02-21 06:48:25 -05:00
Henry de Valence 8c938af579 Spawn tasks for handshake futures.
Previously, we relied on the owner of the handshake future to drive it to
completion.  This meant that there were cases where handshakes might never be
completed, just because nothing was actively polling them.
2020-02-21 06:48:25 -05:00
Henry de Valence 8000f888fd Connect to multiple peers concurrently.
The previous outbound peer connection logic got requests to connect to new
peers and processed them one at a time, making single connection attempts
and retrying if the connection attempt failed.  This was quite slow, because
many connections fail, and we have to wait for timeouts.  Instead, this logic
connects to new peers concurrently (up to 50 at a time).
2020-02-14 18:23:41 -05:00
Henry de Valence 7049f9d891 Add a FindBlocks request to get initial block hashes.
Bitcoin does this either with `getblocks` (returns up to 500 following block
hashes) or `getheaders` (returns up to 2000 following block headers, not
just hashes).  However, Bitcoin headers are much smaller than Zcash
headers, which contain a giant Equihash solution block, and many Zcash
blocks don't have many transactions in them, so the block header is
often similarly sized to the block itself.  Because we're
aiming to have a highly parallel network layer, it seems better to use
`getblocks` to implement `FindBlocks` (which is necessarily sequential)
and parallelize the processing of the block downloads.
2020-02-14 18:23:41 -05:00
Henry de Valence 2082672b3c Remove Response::Error.
Error handling is already handled by Result; we don't need an "inner"
error variant duplicating the outer one.
2020-02-10 09:03:56 -08:00
Henry de Valence 29f901add3 Rename Response::Ok to Response::Nil.
This is a better name because it signals "no data in response" rather
than "Ok", which is semantically mixed with `Ok/Err` of `Result`.
2020-02-10 09:03:56 -08:00
Henry de Valence 5929e05e52 Remove `PushPeers` and ignore unsolicited `addr` messages.
PushPeers is more complicated to thread into the rest of our
architecture (we would need to establish a data path connecting our
service handling inbound requests to the network layer's auto-crawler),
and since we crawl the network automatically anyways, we don't actually
need to accept them in order to get updated address information.

The only possible problem with this approach is that zcashd refuses to
answer multiple address requests from the same connection, ostensibly
for fingerprinting prevention (although it's totally happy to give
exactly the same information, as long as you hang up and reconnect
first, lol).  It's unclear how this will interact with our design -- on
the one hand, it could mean that we don't get new addr information when
we ask, but on the other hand, we may have enough churn in our
connection pool that this isn't a problem anyways.
2020-02-10 09:03:56 -08:00
Henry de Valence 2c0f48b587 Refactor connection logic and try a block request.
Attempting to implement requests for block data revealed a problem with
the previous connection logic.  Block data is requested by sending a
`getdata` message with hashes of the requested blocks; the peer responds
with a sequence of `block` messages with the blocks themselves.

However, this wasn't possible to handle with the previous connection
logic, which could only convert a single Bitcoin message into a
Response.  Instead, we factor out the message handling logic into a
Handler, which can statefully accumulate arbitrary data into a Response
and signal completion.  This is still pretty ugly but it does work.

As a side effect, the HeartbeatNonceMismatch error is removed; because
the Handler now tries to process messages until it comes to a Response,
it just ignores mismatched nonces (and will eventually time out).

The previous Mempool and Transaction requests were removed but could be
re-added in a different form later.  Also, the `Get` prefixes are
removed from `Request` to tidy the name.
2020-02-10 09:03:56 -08:00
Henry de Valence f04f4f0b98 Apply clippy fixes 2020-02-05 12:42:32 -08:00
Henry de Valence 7cc44f4fa9 Move server.rs to connection.rs and change imports. 2020-01-16 13:20:03 -05:00
Henry de Valence 77ad61331c Rename `peer::Server` to `peer::Connection`.
This doesn't change the file path or edit imports so that the diff is easier to review.
2020-01-16 13:20:03 -05:00
Henry de Valence 2965187b91 Upgrade tokio, futures, hyper to released versions. 2019-12-13 17:42:15 -05:00
Deirdre Connolly 82e246d87b
Merge pull request #135 from ZcashFoundation/130
On receipt of a Filter(Load|Add|Clear) message, disconnect from peer
2019-12-05 14:06:05 -05:00
Henry de Valence 36cd6d6e06 cargo fmt 2019-11-27 23:53:36 -05:00
Henry de Valence f58aaac1ae Privately re-export ErrorSlot, ClientRequest in peer.
This means that all sub-modules of `peer` can import everything they need from
the `peer` module itself, without having to be aware of the internal structure
of their sibling modules.
2019-11-27 23:53:36 -05:00
Henry de Valence ad6525574b Rename PeerConnector -> peer::Connector 2019-11-27 23:53:36 -05:00
Henry de Valence 778e49b127 Rename PeerHandshake -> peer::Handshake 2019-11-27 23:53:36 -05:00
Henry de Valence 9ff0fd90dc Rename ServerState -> State.
There's no need to write `Server` every time because it's only used inside of
the server code, and when the handshake service constructs a Server.
2019-11-27 23:53:36 -05:00
Henry de Valence d1b3e8fe6b Rename PeerServer -> peer::Server 2019-11-27 23:53:36 -05:00
Henry de Valence da78603d3a Rename `PeerClient` to `peer::Client`. 2019-11-27 23:53:36 -05:00
Henry de Valence 6db852fab2 Refactor protocol into internal, external modules.
This commit just moves things around and patches import paths.
2019-11-27 05:06:01 -05:00
Deirdre Connolly d78ead4a1a Removed unused trait import 2019-11-26 19:35:49 -05:00
Deirdre Connolly b9c27e5683 Handle Response::Error and send Message::Reject generated from a PeerError::Rejected 2019-11-26 19:35:49 -05:00
Deirdre Connolly f5f1fe9bbc Handle incoming Reject messages when we expect a response 2019-11-26 19:35:49 -05:00
Deirdre Connolly 49c5265d41 Add Rejected variant to PeerError enum, for now 2019-11-26 19:35:49 -05:00
Deirdre Connolly bae9347f6e Rustfmt 2019-11-26 19:35:49 -05:00
Deirdre Connolly 189d89a7fc Handle 'mempool' messages as 'GetMempool' requests
With a 'Transactions' response that gets turned into an 'Inv(Vec<InventoryHash::Tx>)' message.

We don't yet handle a response from our peer for a 'mempool', which will have to be
a more generic 'Inv' type because we might receive transaction hashes we don't know about yet.

Pertains to #26
2019-11-18 15:55:25 -05:00
Henry de Valence 2ac77ab704 fmt 2019-11-13 18:43:18 -05:00
Deirdre Connolly 4d3ab201e6 seed command seems to be functional
Moved SeedService out of the command closure Command currently spawns
a tokio task to DOS the seed service with `Request::GetPeers` every
second.

Pertains to #54
2019-11-12 22:39:47 -05:00
Henry de Valence c3ec235a5b Suppress unused import warnings. 2019-10-22 19:06:08 -07:00
Henry de Valence ed2ee9d42f Add a PeerConnector wrapper around PeerHandshake 2019-10-22 19:06:08 -07:00
Henry de Valence 9e2678d76c Rename PeerConnector to PeerHandshake.
It's only responsible for doing the handshakes, so it should be named that way,
and then we can have a Connector responsible for actually opening the TCP
connection.
2019-10-22 19:06:08 -07:00
Henry de Valence 121cea610b Unlink peer spans from their creation details. 2019-10-22 19:06:08 -07:00
Henry de Valence 4055eb8889 bugfix: ensure the PeerServer always calls fail_with before exit
This caused a panic in the PeerSet when remote peers disconnected from us.
2019-10-22 17:55:09 -04:00
Deirdre Connolly 3de34290e6 Construct LIVE_PEER_DURATION from other timeout and interval constants
Use constants::HEARTBEAT_INTERVAL in our ping generator, add a test to check that LIVE_PEER_DURATION
is consistent with the other constants.
2019-10-21 15:55:18 -04:00
Deirdre Connolly 8588c44bcf Add a comment about not cloning the server channel any more than we are 2019-10-21 15:55:18 -04:00
Deirdre Connolly 61a07c67ef Inside tokio::spawn, loop over Iterator stream and send ClientRequest
msgs on the channel instead

Related to #49
2019-10-21 15:55:18 -04:00
Deirdre Connolly e65f5a05ea Broken: I can't seem to return either an impl Future or Result to satisfy for_each 2019-10-21 15:55:18 -04:00
Deirdre Connolly 3548998980 Set server state to Failed if a response to a heartbeat Ping never comes 2019-10-21 15:55:18 -04:00
Deirdre Connolly adffc4239d Partially complete heartbeats to peer 2019-10-21 15:55:18 -04:00
Henry de Valence b03a83fa86 Simplify TimestampCollector.
Previously, the TimestampCollector was intended to own the address book
data, so it was intended to be cloneable and hold shared state among all
of its handles.  This is now modeled more directly by an
`Arc<Mutex<AddressBook>>`, so the only functionality left in the
`TimestampCollector` is setting up the inital worker, which is better
called `spawn` than `new`.

This also fixes a problem introduced in the previous commit where the
`TimestampCollector` was dropped, causing the worker task to shut down
early.
2019-10-21 14:40:03 -04:00
Henry de Valence 15a698b23c Use MetaAddr in the timestamp collector.
We will need service bits information to report on peer addresses, so we
need to collect it in the timestamp collector.
2019-10-21 14:40:03 -04:00
Henry de Valence ad43a61fb4 Ensure that all types appearing in public types are exported. 2019-10-18 16:11:01 -07:00
Henry de Valence d4dc4f0d04 Add tracing output on unhandled peer requests 2019-10-18 16:11:01 -07:00
Henry de Valence 63cf340ab4 Add fields to zebra-network Config. 2019-10-18 16:11:01 -07:00
Henry de Valence ff27334e81 Make PeerConnector tower::Buffer'able 2019-10-17 09:34:18 -07:00
Henry de Valence db7ac53f3b Add a Mutex<HashSet<Nonce>> to detect self-conns. 2019-10-17 09:34:18 -07:00
Henry de Valence ed335e68f4 Remove outdated comment
Now that the `PeerConnector` handles both incoming and outgoing
handshakes, determining the next peer address is definitely out of scope
-- it takes a pre-existing tcp connection.
2019-10-17 09:34:18 -07:00
Henry de Valence 8a1aa71736 Modify PeerConnector to also handle inbound conns.
Because the Bitcoin handshake is symmetric, we can reuse the same logic
for both incoming and outgoing connections.
2019-10-17 09:34:18 -07:00
Henry de Valence f6e62b0f5e Remove failure from zebra-chain, zebra-network.
Failure uses a distinct Fail trait rather than the standard library's
Error trait, which causes a lot of interoperability problems with tower
and other Error-using crates.  Since failure was created, the standard
library's Error trait was improved, and its conveniences are now
available without the custom Fail trait using `thiserror` (for easy
error derives) and `anyhow` (for a better boxed Error).
2019-10-16 13:16:52 -04:00
Deirdre Connolly 199038e6b8 Rename bound vars in match arms for PeerServer state machine
Co-Authored-By: Henry de Valence <hdevalence@hdevalence.ca>
2019-10-15 14:49:11 -04:00
Henry de Valence 373a8fbcfd Refactor PeerServer event loop to avoid select! 2019-10-15 14:49:11 -04:00
Henry de Valence 16f51e4d48 Add a timeout to the `PeerServer` event loop.
I think this code could be cleaned up significantly (e.g., removing the
other use of select!) but that's potentially a larger change than this
PR.
2019-10-15 14:49:11 -04:00
Henry de Valence ae1a164ff8
Beginning of peerset implementation. (#62)
* Don't expose submodules of zebra_network::peer.

* PeerSet, PeerDiscover stubs.

Co-authored-by: Deirdre Connolly <deirdre@zfnd.org>

* Initial work on PeerSet.

This is adapted from the MIT-licensed tower-balance implementation.

* Use PeerSet in the connect stub.
2019-10-10 18:15:24 -07:00
Henry de Valence f284f6d6cf Tweak debug output in PeerConnector handshake. 2019-10-08 23:34:16 -04:00
Henry de Valence fb2b502eb9 Add a `Config` struct to zebra-network.
This struct is pulled into the main abscissa config as a subsection.
2019-10-08 23:34:16 -04:00
Henry de Valence 1266653be2
Handle error conversions properly. (#56)
This adds a type alias, BoxedStdError, for a boxed std::error::Error
trait object, and uses it in the where bounds for the generic service
code.  In the future, we may want to standardize on using
std::error::Error exclusively, but we would then possibly lose out on
backtrace information.
2019-10-08 13:49:12 -07:00
Henry de Valence ed608f7231
Initial tower-based peer implementation. (#17)
Add a tower-based peer implementation.  

Tower provides middleware for request-response oriented protocols, while Bitcoin/Zcash just send messages which could be interpreted either as requests or responses, depending on context.  To bridge this mismatch we define our own internal request/response protocol, and implement a per-peer event loop that scans incoming messages and interprets them either as requests from the remote peer to our node, or as responses to requests we made previously.  This is performed by the `PeerService` task, and a corresponding `PeerClient: tower::Service` can send it requests.  These tasks are themselves created by a `PeerConnector: tower::Service` which dials a remote peer and performs a handshake.
2019-10-07 15:36:16 -07:00