Commit Graph

349 Commits

Author SHA1 Message Date
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 31651cf87c Fix copy-paste bug in Codec
Co-authored-by: George Tankersley <george@zfnd.org>
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
Deirdre Connolly 980ce4593b Fix merge artifacts in Cargo.toml 2019-10-17 09:33:10 -07:00
Deirdre Connolly 0db69addec Add custom Debug impl for DecodeState
Relates to #63
2019-10-17 09:33:10 -07:00
Deirdre Connolly 051dc2f039 Implement custom Debug for Magic types
Related to #63
2019-10-17 09:33:10 -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 fc872ea03f Remove async-await feature of futures. 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 b45efbdaf2
Add peer count data to TimestampData::update trace (#66)
* Add peer count data to TimestampData::update trace

* Update docstring typo
2019-10-11 12:41:37 -07: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
Deirdre Connolly dc18e8f24c Remove .expect()s for block and transaction, they might fail for writer reasons 2019-10-09 22:25:37 -04:00
Deirdre Connolly 4ec7590b42 Add placeholders for remaining messages in write_body 2019-10-09 22:25:37 -04:00
Deirdre Connolly d8986098c6 Add write_body implementations for GetData, NotFound, and a placeholder for Reject 2019-10-09 22:25:37 -04:00
Deirdre Connolly 483d6584f9 Add Block msg reader and writers, and Tx msg writer 2019-10-09 22:25:37 -04:00
Deirdre Connolly 8dc9181610 Fill out write_body for GetBlocks, GetHeaders, Headers messages 2019-10-09 22:25:37 -04:00
Deirdre Connolly a0302a5507 Implement read_getaddr 2019-10-09 22:25:37 -04:00
Deirdre Connolly cfbe8dfdbf Add comments about the 500 blocks /2000 headers max numbers are speculative based on Bitcoin docs 2019-10-09 22:25:37 -04:00
Deirdre Connolly 5acdaa6d2f Remove some defunct XXXs 2019-10-09 22:25:37 -04:00
Deirdre Connolly dd1b9166b0 Implement Zcash(De)Serialize for BlockHeaderHash, use general read_list for getheaders/headers 2019-10-09 22:25:37 -04:00
Deirdre Connolly eed69063f6 Add read_list to ReadZcashExt 2019-10-09 22:25:37 -04:00
Deirdre Connolly d470dd9709 Parse messages 2019-10-09 22:25:37 -04:00
Deirdre Connolly b991c413cd Parse GetBlock messages 2019-10-09 22:25:37 -04:00
Deirdre Connolly 7632d5b8cc Abstract the common case of a message with a Vec<InventoryHash> 2019-10-09 22:25:37 -04:00
Deirdre Connolly 9699ef2fa1 Codec::read_tx() 2019-10-09 22:25:37 -04:00
Deirdre Connolly 565dc92afe Support a response message 2019-10-09 22:25:37 -04:00
Henry de Valence 8a3b4f48fc Move all git dependencies to published crates. (#58)
The earlier issues with version resolution incompatibilities are now
resolved, and all the upstream changes we made to tracing are released.
2019-10-09 00:10:01 -04:00
Henry de Valence 6f79f2843d Use emojis in user-agent to detect Unicode support. 2019-10-08 23:34:16 -04: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 92dc7a5ea1
Fix authorship, license information. (#55)
* Fix authorship, license information.

I *thought* I had done a sed pass over the Cargo defaults when doing
repository initialization, but I guess I missed it or something.
Anyways, fixed now.
2019-10-08 09:25:59 -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
Henry de Valence f5dca597dd Replace PeerServices(u64) with a bitflags struct.
This gives considerably better ergonomics.
2019-10-01 01:07:56 -04:00
Henry de Valence 9603a29399 Rename `Services` to `PeerServices`.
This field is called `services` in Bitcoin and Zcash, but because we use
that word internally for other purposes, calling it `PeerServices`
disambiguates the meaning to "the services advertised by the peer",
rather than, e.g., a `tower::Service`.
2019-10-01 01:07:56 -04:00
Deirdre Connolly 2739970113 Fill out TransactionHash and rename
Resolves #35
2019-09-27 19:22:34 -07:00
Deirdre Connolly b21b09bf8e Moved stub TxHash into zebra_chain::transaction 2019-09-27 19:22:34 -07:00
Deirdre Connolly 29591df47e Use the BlockHeaderHash from zebra-chain in the Inv message parsing 2019-09-27 19:22:34 -07:00
Henry de Valence 0a85be285d Add addr, getaddr serialization. 2019-09-27 20:41:45 -04:00
Henry de Valence b426630613 Clarify comment in decoder state. 2019-09-27 20:41:45 -04:00
Henry de Valence 422c783a47 Rename Message::Inventory -> Message::Inv
I don't feel super strongly about this change, so I'm happy to drop it,
but it makes the parsing match statements line up nicely and aligns
naming with the naming used in Bitcoin.
2019-09-27 20:41:45 -04:00
Henry de Valence 958fca8e68 Parse inv messages, refactor inventory vectors.
This removes the inventory vector structs from `zebra-chain` (as they
are really part of the network protocol) and refactors them into a
single `InventoryHash` type.  This corresponds to Bitcoin's "inventory
vector" but with a different, better name (it's not a vector, it's just
a typed hash of some other item).
2019-09-27 20:41:45 -04:00
Henry de Valence ab06750db3 zebra-network: move types -> protocol::types
These types are used for protocol messages, so it makes more sense to
keep them scoped with the protocol handling, rather than other
networking logic.
2019-09-27 20:41:45 -04:00
Deirdre Connolly 35f03dc55d Make Message.Block just point at a Block type, in codec call block.zcash_serialize() 2019-09-26 23:41:25 -04:00
Deirdre Connolly 3f2a1b4f2c Move around MerkleTree* structs 2019-09-26 23:41:25 -04:00
Deirdre Connolly 677d53897f Use Vec<u8> for the equihash solution instead of [u8; 1344] for now 2019-09-26 23:41:25 -04:00
Deirdre Connolly cecbb1cc0a Fill out the Block Message type
Should we serialize out `Block` or leave explicit like so? ¯\_(ツ)_/¯
2019-09-26 23:41:25 -04:00
Henry de Valence 48a5054c87 Delete unused variable.
This is no longer required because the body reader methods have access
to the version via the codec state.
2019-09-25 14:59:47 -07:00
Henry de Valence 0196c2c4cd Place header encoding prior to body encoding. 2019-09-25 14:59:47 -07:00
Henry de Valence 94a07b05cc Move HEADER_LEN constant to top of file. 2019-09-25 14:59:47 -07:00
Henry de Valence 28904e01c7 Trace the decoded message in the decoder. 2019-09-25 14:59:47 -07:00
Henry de Valence ea1b60d8e3 Make message body reader fns part of Codec. 2019-09-25 14:59:47 -07:00
Henry de Valence 4e1285b568 Refactor message serialization as a tokio codec.
This provides a significantly cleaner API to consumers, because it
allows using adaptors that convert a TCP stream to a stream of messages,
and potentially allows more efficient message handling.
2019-09-25 14:59:47 -07:00
Henry de Valence 0b1acc50c3 Make a new protocol module with message submodule.
This allows us to organize all of the Bitcoin-Zcash specific parts of
the protocol into a subtree.
2019-09-25 14:59:47 -07:00
Henry de Valence c8a3d47b56 Use tracing::instrument and monitor for messages. 2019-09-23 22:17:12 -04:00
Henry de Valence 15ca12a2f5 Add a `connect` command for testing.
With `./src/zcashd -debug=net -logips=1`:
```
2019-09-19 15:24:38 Added connection to 127.0.0.1:35932 peer=1
2019-09-19 15:24:38 connection from 127.0.0.1:35932 accepted
2019-09-19 15:24:38 socket closed
2019-09-19 15:24:38 disconnecting peer=1
```

With `RUST_LOG="trace"`, `cargo run connect`:
```
Sep 19 08:24:24.530  INFO zebrad::commands::connect: version=Version { version: Version(170007), services: Services(1), timestamp: 2019-09-19T15:24:24.530059300Z, address_recv: (Services(1), V4(127.0.0.1:8233)), address_from: (Services(1), V4(127.0.0.1:9000)), nonce: Nonce(1), user_agent: "Zebra Connect", start_height: BlockHeight(0), relay: false }
Sep 19 08:24:24.530 TRACE Task::run: tokio_executor::threadpool::task: state=Running
Sep 19 08:24:24.530 DEBUG Task::run: tokio_net::driver::reactor: adding I/O source token=0
Sep 19 08:24:24.530  INFO zebrad::commands::connect: version_bytes="24e9276476657273696f6e000000000063000000cb30ab03179802000100000000000000a89d835d00000000010000000000000000000000000000000000ffff7f0000012029010000000000000000000000000000000000ffff7f000001232801000000000000000d5a6562726120436f6e6e6563740000000000"
Sep 19 08:24:24.530 TRACE Task::run: log: registering with poller
```
2019-09-22 17:27:08 -04:00
Henry de Valence 976a81e7b9 Use failure::Error in zebra_network::message.
This gives backtraces and more ergonomic errors, at the cost of possible
allocations (which we do here anyways).
2019-09-22 17:06:07 -04:00
Henry de Valence 9fe8f22a84 Add verack, ping, pong serialization. 2019-09-22 17:06:07 -04:00
Henry de Valence 3b51056857 Change Message serialization to async send/recv.
Because we want to be able to read messages from async sources (like a
tcp socket), we need to have at least async header parsing logic, so
that we can correctly determine how many bytes to await to parse each
message, so it makes sense for the entire message parsing functions
to be async.

Because we perform message serialization into async readers and writers
in the context of sending messages over the network, code using these
functions is more clear with these names.
2019-09-22 17:06:07 -04:00
Henry de Valence fa4ba442eb Add a MIN_VERSION constant to zebra_network.
When we perform a handshake with a remote peer, we need to encode the
version messages with a particular network version before we find out
what the remote peer's version preference is.  So in addition to having
a CURRENT_VERSION constant (which represents our preference), we need to
have a MIN_VERSION during the handshake (and later to determine whether
we'll talk to the peer at all).
2019-09-22 17:06:07 -04:00
Henry de Valence 0cb439301a Add a USER_AGENT constant to zebra_network. 2019-09-22 17:06:07 -04:00
Henry de Valence 252dce1bad Use rand::thread_rng to impl Default for Nonce. 2019-09-22 17:06:07 -04:00
Henry de Valence b3e094bc40 Clean parsing via ReadZcashExt read-array helpers.
This adds convenience methods to `ReadZcashExt` that read 4 and 12 byte
fixed size arrays from the `Reader`, making the actual parsing code more
legible.

Closes #10.
2019-09-19 12:53:16 -04:00
Henry de Valence f45bbeba98
Replace `Version` `MetaAddr` with `(Services, SocketAddr)`. (#12)
* Replace Version MetaAddr by (Services, SocketAddr).

The version handshake message doesn't include last-seen timestamps for
the address fields, unlike other messages, so instead of modeling the
message data with a `MetaAddr` (which includes a timestamp), we should
just use a tuple.

* Simplify try_read_version implementation.

Because we no longer need to construct fake timestamps for the
`MetaAddr` fields, we don't need to use any of the parsed fields while
parsing later fields, and we can neatly wrap up the entire parsing logic
into a single expression.

* fmt

I didn't have the toolchain-specified `rustfmt` because I was mostly
offline and couldn't download it.
2019-09-19 09:38:02 -07:00
Deirdre Connolly 73740841e1 Move `Transaction` and related types to their own module (#9)
* Move `Transaction` and related types to their own module

Resolves #6

* Fix references to `Transaction` after move
2019-09-19 07:45:37 -07:00
Deirdre Connolly 3032da8b1b Remove defunct and dead try_read 2019-09-18 17:32:06 -04:00
Deirdre Connolly 8edbc7b744 Resolve 'warning: unused that must be used' error 2019-09-18 17:32:06 -04:00
Deirdre Connolly 46984cbb27 Add `tx` message, along with `Transaction`, `Transaction(In|Out)put`, and `OutPoint` types 2019-09-18 17:32:06 -04:00
Deirdre Connolly cc9da18554 Use an Option around optional Reject message data
And replace Timestamp with chrono::DateTime
2019-09-18 17:32:06 -04:00
Henry de Valence adc421f7fe Implement ZcashDeserialize for Message::Version.
This has a test that the serialization implementation round trips
correctly, but is very much a work in progress.  Issues with this code
include:

The deserialization logic for message headers is somewhat ugly because
of a lack of a convenient idiom for reading a few bytes at a time into a
fixed-size array.  Perhaps this could be fixed with an extension trait,
or avoided altogether by using `u32`s instead of `[u8; 4]`, even when
the latter is the "morally correct type".

Deserialization does an extra allocation, copying the body into a
temporary buffer.  This avoids two problems: 1) capping the number of
bytes that can be read by the `Read`er passed into the body parser and
2) allows making two passes over the body data, one to parse it and one
to compute the checksum.

We could avoid making two passes over the body by computing the checksum
simultaneously with the parsing. A convenient way to do this would be to
define a

```
struct ChecksumReader<R: Read> {
    inner: R,
    digest: Sha256,
}

impl<R: Read> Read for ChecksumReader<R> { /* ... */ }
```

and implement `Read` for `ChecksumReader` to forward reads from the
inner reader, copying data into the digest object as it does so.  (It
could also have a maximum length to enforce that we do not read past the
nominal end of the body).

A similar `ChecksumWriter` could be used during serialization, although
because the checksum is at the beginning rather than the end of the
message it does not help avoid an allocation there.  It could also be
generic over a `Digest` implementation, although because we need a
truncated double-SHA256 we would have to write a custom `Digest`
implementation, so this is probably not worthwhile unless we have other
checksum types.

Finally, this does very minimal testing -- just round-trip serialization
on a single message.  It would be good to build in support for
property-based testing, probably using `proptest`; if we could define
generation and shrinking strategies for every component type of every
message, we could do strong randomized testing of the serialization.
2019-09-18 17:32:06 -04:00
Henry de Valence 733d090b9b Add missing derives to newtypes. 2019-09-18 17:32:06 -04:00
Henry de Valence 32cf74db39 Move serialization to zebra-chain, rework traits.
The core serialization logic is now in zebra-chain and consists of two
pairs of traits:

These are analogues of the Serde `Serialize` and `Deserialize` traits,
but explicitly intended for consensus-critical serialization formats.
Thus some struct `Foo` may have derived `Serialize` and `Deserialize`
implementations for (internal) use with Serde, and explicitly-written
`ZcashSerialize` and `ZcashDeserialize` implementations for use in
consensus-critical contexts.  The consensus-critical implementations
provide `zcash`-prefixed `zcash_serialize` and `zcash_deserialize`
methods to make it clear in client contexts that the serialization is
consensus-critical.

These are utility traits, analogous to the `ReadBytesExt` and
`WriteBytesExt` traits provided by `byteorder`.  A generic
implementation is provided for any `io::Read` or `io::Write`, so that
bringing the traits into scope adds additional Zcash-specific traits to
generic readers and writers -- for instance, writing a `u64` in the
Bitcoin "CompactSize" format.
2019-09-18 17:32:06 -04:00
Henry de Valence 78b1aabed0 Deserialize Bitcoin-encoded strings. 2019-09-18 17:32:06 -04:00
Henry de Valence 715ed52617 Deserialize Bitcoin-encoded IP addresses. 2019-09-18 17:32:06 -04:00
Henry de Valence 3c32beb8f0 Add a &'static str error message to ParseError. 2019-09-18 17:32:06 -04:00
Henry de Valence d847dc1356 Start implementing serialization for Version. 2019-09-18 17:32:06 -04:00
Henry de Valence b98e1c7853 Add ZcashSerialization impls for some std types. 2019-09-18 17:32:06 -04:00
Henry de Valence 1f280b7bb8 Make MetaAddr fields public. 2019-09-18 17:32:06 -04:00
Henry de Valence 8a3cabc686 Define Magic newtype as `[u8; 4]`, not `u32`.
The magic value isn't a u32, it's a byte string, so specifying it as
such avoids ambiguity about endianness.
2019-09-18 17:32:06 -04:00
Henry de Valence 00cc1284ae Add a stub ZcashSerialization trait.
There are a few unresolved questions marked in the doc comment for the trait;
we can resolve them later and rework the trait as we map everything out.
2019-09-18 17:32:06 -04:00
Henry de Valence 73cd06b4dc Add derived impls to newtypes 2019-09-18 17:32:06 -04:00
Henry de Valence c3b7dcdfbe Add Read/WriteZcashExt extension traits.
Currently these just have write_compactsize and read_compactsize methods which
allow reading and writing u64s to any `Read` or `Write` implementation using
the Bitcoin "CompactSize" variable integer encoding.

These methods read and write u64s rather than defining a new `CompactSize`
type, because the `CompactSize` is just an encoding detail, not a different
type with any distinct meaning.
2019-09-18 17:32:06 -04:00
Henry de Valence 50f749a817 Try writing message headers. 2019-09-18 17:32:06 -04:00
Henry de Valence cf63f00171 Add a Magic type for network magics. 2019-09-18 17:32:06 -04:00
Henry de Valence b9af047a09 Introduce a `MetaAddr` type replacing `NetworkAddress`.
The `NetworkAddress` type was a `(Services, SocketAddr)` pair as used in the
`version` handshake message, described as the `net_addr` struct in the Bitcoin
wiki protocol documentation.  However, all of the other uses of the `net_addr`
struct are a `(Timestamp, Services, SocketAddr)` pair (where the timestamp is
the last-seen time of the peer), and the timestamp is omitted only during the
`version` messages, which are used only during the handshake, so it seems
better to include the timestamp field and omit it during serialization of
`version` packets.
2019-09-18 17:32:06 -04:00
Henry de Valence 1d0517fe56 Split parts of message.rs into constants.rs, types.rs 2019-09-18 17:32:06 -04:00
Henry de Valence eeb0ab7c43 fixup! Add InventoryType, InventoryVector, and Message::{Inventory, GetData, NotFound} 2019-09-18 17:32:06 -04:00
Deirdre Connolly a2e50833be Add InventoryType, InventoryVector, and Message::{Inventory, GetData, NotFound} 2019-09-18 17:32:06 -04:00
Henry de Valence 7fb71a7a9e Replace Timestamp with chrono::DateTime<Utc> 2019-09-18 17:32:06 -04:00
Deirdre Connolly fa8b5290b5 Add Reject message type and RejectReason enum 2019-09-18 17:32:06 -04:00
Deirdre Connolly a4a21138d0 Update user_agent docstring
Co-authored-by: Henry de Valence <hdevalence@hdevalence.ca>
2019-09-18 17:32:06 -04:00
Deirdre Connolly c39d2c7510 Doc comments for various structures and fields
Co-authored-by: Henry de Valence <hdevalence@hdevalence.ca>
2019-09-18 17:32:06 -04:00
Deirdre Connolly ac0d9732a0 WIP: Version message and various sub structures
Co-authored-by: Henry de Valence <hdevalence@hdevalence.ca>
2019-09-18 17:32:06 -04:00
Henry de Valence 8c2b066885 Add more message variants. 2019-09-18 17:32:06 -04:00
Deirdre Connolly 42412ec2a8 Some line breaks for readability 2019-09-18 17:32:06 -04:00
Henry de Valence 80308f85e1 Add a skeleton enum for network messages. 2019-09-18 17:32:06 -04:00
Henry de Valence ec363d2d41 Create workspace skeleton based on design.md 2019-08-29 14:46:54 -07:00