//! Definitions of network messages. use std::net::SocketAddr; use chrono::{DateTime, Utc}; use zebra_chain; /// A Bitcoin-like network message for the Zcash protocol. /// /// The Zcash network protocol is mostly inherited from Bitcoin, and a list of /// Bitcoin network messages can be found [on the Bitcoin /// wiki][btc_wiki_protocol]. /// /// That page describes the wire format of the messages, while this enum stores /// an internal representation. The internal representation is unlinked from the /// wire format, and the translation between the two happens only during /// serialization and deserialization. For instance, Bitcoin identifies messages /// by a 12-byte ascii command string; we consider this a serialization detail /// and use the enum discriminant instead. (As a side benefit, this also means /// that we have a clearly-defined validation boundary for network messages /// during serialization). /// /// [btc_wiki_protocol]: https://en.bitcoin.it/wiki/Protocol_documentation // // XXX not all messages are filled in yet. Messages written as { /* XXX add // fields */ } are explicitly incomplete and we need to define a mapping between // the serialized message data and the internal representation. Note that this // is different from messages like GetAddr which have no data (and so have no // fields). pub enum Message { /// A `version` message. /// /// Note that although this is called `version` in Bitcoin, its role is really /// analogous to a `ClientHello` message in TLS, used to begin a handshake, and /// is distinct from a simple version number. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#version) Version { /// The network version number supported by the sender. version: Version, /// The network services advertised by the sender. services: Services, /// The time when the version message was sent. timestamp: DateTime, /// The network address of the node receiving this message. address_receiving: NetworkAddress, /// The network address of the node emitting this message. address_from: NetworkAddress, /// Node random nonce, randomly generated every time a version /// packet is sent. This nonce is used to detect connections /// to self. nonce: Nonce, /// The Zcash user agent advertised by the sender. user_agent: String, /// The last block received by the emitting node. start_height: zebra_chain::types::BlockHeight, /// Whether the remote peer should announce relayed /// transactions or not, see [BIP 0037](https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki) relay: bool, }, /// A `verack` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#verack) Verack, /// A `ping` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#ping) Ping(Nonce), /// A `pong` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#pong) Pong( /// The nonce from the `Ping` message this was in response to. Nonce, ), /// A `reject` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#reject) Reject { /// Type of message rejected. // Q: can we just reference the Type, rather than instantiate an instance of the enum type? message: Box, /// RejectReason code relating to rejected message. ccode: RejectReason, /// Human-readable version of rejection reason. reason: String, /// Optional extra data provided for some errors. // Currently, all errors which provide this field fill it with // the TXID or block header hash of the object being rejected, // so the field is 32 bytes. // // Q: can we tell Rust that this field is optional? Or just // default its value to an empty array, I guess. data: [u8; 32], }, /// An `addr` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#addr) Addr { /// Number of address entries (max: 1000) count: u16, /// Address of other nodes on the network, preceeded by a timestamp. // Starting version 31402, addresses are prefixed with a // timestamp. If no timestamp is present, the addresses should // not be relayed to other peers, unless it is indeed // confirmed they are up. // // XXX: I don't know how this serializes. address_list: (DateTime, Vec), }, /// A `getaddr` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#getaddr) GetAddr, /// A `block` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#block) Block {/* XXX add fields */}, /// A `getblocks` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#getblocks) GetBlocks {/* XXX add fields */}, /// A `headers` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#headers) Headers {/* XXX add fields */}, /// A `getheaders` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#getheaders) GetHeaders {/* XXX add fields */}, /// An `inv` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#inv) // XXX the bitcoin reference above suggests this can be 1.8 MB in bitcoin -- maybe // larger in Zcash, since Zcash objects could be bigger (?) -- does this tilt towards // having serialization be async? Inventory { /// Number of inventory entries. count: u64, /// Inventory vectors. inventory: Vec, }, /// A `getdata` message. /// /// `getdata` is used in response to `inv`, to retrieve the content of /// a specific object, and is usually sent after receiving an `inv` /// packet, after filtering known elements. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#getdata) GetData { /// Number of inventory entries. count: u64, /// Inventory vectors. inventory: Vec, }, /// A `notfound` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#notfound) // See note above on `Inventory`. NotFound { /// Number of inventory entries. count: u64, /// Inventory vectors. inventory: Vec, }, /// A `tx` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#tx) Tx {/* XXX add fields */}, /// A `mempool` message. /// /// This was defined in [BIP35], which is included in Zcash. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#mempool) /// [BIP35]: https://github.com/bitcoin/bips/blob/master/bip-0035.mediawiki Mempool {/* XXX add fields */}, /// A `filterload` message. /// /// This was defined in [BIP37], which is included in Zcash. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#filterload.2C_filteradd.2C_filterclear.2C_merkleblock) /// [BIP37]: https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki FilterLoad {/* XXX add fields */}, /// A `filteradd` message. /// /// This was defined in [BIP37], which is included in Zcash. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#filterload.2C_filteradd.2C_filterclear.2C_merkleblock) /// [BIP37]: https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki FilterAdd {/* XXX add fields */}, /// A `filterclear` message. /// /// This was defined in [BIP37], which is included in Zcash. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#filterload.2C_filteradd.2C_filterclear.2C_merkleblock) /// [BIP37]: https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki FilterClear {/* XXX add fields */}, /// A `merkleblock` message. /// /// This was defined in [BIP37], which is included in Zcash. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#filterload.2C_filteradd.2C_filterclear.2C_merkleblock) /// [BIP37]: https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki MerkleBlock {/* XXX add fields */}, } // Q: how do we want to implement serialization, exactly? do we want to have // something generic over stdlib Read and Write traits, or over async versions // of those traits? /// A protocol version magic number. pub struct Version(pub u32); /// Bitfield of features to be enabled for this connection. // Tower provides utilities for service discovery, so this might go // away in the future in favor of that. pub struct Services(pub u64); /// A network address but with some extra flavor. /// /// When a network address is needed somewhere, this structure is /// used. Network addresses are not prefixed with a timestamp in the /// version message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#Network_address) pub struct NetworkAddress(pub Services, pub SocketAddr); /// A nonce used in the networking layer to identify messages. pub struct Nonce(pub u64); /// Reject Reason CCodes /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#reject) #[repr(u8)] #[allow(missing_docs)] pub enum RejectReason { Malformed = 0x01, Invalid = 0x10, Obsolete = 0x11, Duplicate = 0x12, Nonstandard = 0x40, Dust = 0x41, InsufficientFee = 0x42, Checkpoint = 0x43, }