From ae376a8f098e0f4f7e8258fd0c1c9d27a6e1cb07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Tue, 12 Feb 2019 11:09:00 +0100 Subject: [PATCH 01/16] First proposal of macro to implement SyncPacket --- Cargo.lock | 20 +++--- ethcore/sync/Cargo.toml | 2 +- ethcore/sync/src/chain/handler.rs | 1 - ethcore/sync/src/chain/supplier.rs | 1 - ethcore/sync/src/chain/sync_packet.rs | 96 +++++++-------------------- ethcore/sync/src/lib.rs | 4 +- util/syncpacketid_derive/Cargo.toml | 13 ++++ util/syncpacketid_derive/src/lib.rs | 69 +++++++++++++++++++ 8 files changed, 119 insertions(+), 87 deletions(-) create mode 100644 util/syncpacketid_derive/Cargo.toml create mode 100644 util/syncpacketid_derive/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index d4f20132d53..a1658410994 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -588,14 +588,6 @@ dependencies = [ "heapsize 0.4.2 (git+https://github.com/cheme/heapsize.git?branch=ec-macfix)", ] -[[package]] -name = "enum_primitive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "env_logger" version = "0.5.13" @@ -1116,7 +1108,6 @@ name = "ethcore-sync" version = "1.12.0" dependencies = [ "common-types 0.1.0", - "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", "ethcore-io 1.12.0", @@ -1141,6 +1132,7 @@ dependencies = [ "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syncpacketid_derive 0.1.0", "trace-time 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "triehash-ethereum 0.2.0", ] @@ -3664,6 +3656,15 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syncpacketid_derive" +version = "0.1.0" +dependencies = [ + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "synom" version = "0.11.3" @@ -4519,7 +4520,6 @@ dependencies = [ "checksum edit-distance 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3bd26878c3d921f89797a4e1a1711919f999a9f6946bb6f5a4ffda126d297b7e" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88d4851b005ef16de812ea9acdb7bece2f0a40dd86c07b85631d7dafa54537bb" -"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "checksum eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)" = "" diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index 9db93316261..63da1924225 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -9,7 +9,6 @@ authors = ["Parity Technologies "] [dependencies] common-types = { path = "../types" } -enum_primitive = "0.1.1" ethcore = { path = ".." } ethcore-io = { path = "../../util/io" } ethcore-light = { path = "../light" } @@ -30,6 +29,7 @@ parity-bytes = "0.1" parking_lot = "0.7" rand = "0.4" rlp = { version = "0.3.0", features = ["ethereum"] } +syncpacketid_derive = { path = "../../util/syncpacketid_derive" } trace-time = "0.1" triehash-ethereum = {version = "0.2", path = "../../util/triehash-ethereum" } diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs index 63ab8916139..e94e852dbdb 100644 --- a/ethcore/sync/src/chain/handler.rs +++ b/ethcore/sync/src/chain/handler.rs @@ -17,7 +17,6 @@ use api::WARP_SYNC_PROTOCOL_ID; use block_sync::{BlockDownloaderImportError as DownloaderImportError, DownloadAction}; use bytes::Bytes; -use enum_primitive::FromPrimitive; use ethcore::error::{Error as EthcoreError, ErrorKind as EthcoreErrorKind, ImportErrorKind, BlockError}; use ethcore::snapshot::{ManifestData, RestorationStatus}; use ethcore::verification::queue::kind::blocks::Unverified; diff --git a/ethcore/sync/src/chain/supplier.rs b/ethcore/sync/src/chain/supplier.rs index 7e71e6aeec7..73e9244516a 100644 --- a/ethcore/sync/src/chain/supplier.rs +++ b/ethcore/sync/src/chain/supplier.rs @@ -15,7 +15,6 @@ // along with Parity Ethereum. If not, see . use bytes::Bytes; -use enum_primitive::FromPrimitive; use ethereum_types::H256; use network::{self, PeerId}; use parking_lot::RwLock; diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index 3891090f65e..18fe84201d7 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -22,6 +22,8 @@ //! to convert to/from the packet id values transmitted over the //! wire. + + use api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; use network::{PacketId, ProtocolId}; @@ -31,87 +33,37 @@ use network::{PacketId, ProtocolId}; /// to enum variants. This implicitly provides a mechanism to /// check whether a given packet id is known, and to prevent /// packet id clashes when defining new ids. -enum_from_primitive! { -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, SyncPackets, PartialEq)] pub enum SyncPacket { - StatusPacket = 0x00, - NewBlockHashesPacket = 0x01, - TransactionsPacket = 0x02, - GetBlockHeadersPacket = 0x03, - BlockHeadersPacket = 0x04, - GetBlockBodiesPacket = 0x05, - BlockBodiesPacket = 0x06, - NewBlockPacket = 0x07, - - GetNodeDataPacket = 0x0d, - NodeDataPacket = 0x0e, - GetReceiptsPacket = 0x0f, - ReceiptsPacket = 0x10, - - GetSnapshotManifestPacket = 0x11, - SnapshotManifestPacket = 0x12, - GetSnapshotDataPacket = 0x13, - SnapshotDataPacket = 0x14, - ConsensusDataPacket = 0x15, - PrivateTransactionPacket = 0x16, - SignedPrivateTransactionPacket = 0x17, -} + #[eth] StatusPacket = 0x00, + #[eth] NewBlockHashesPacket = 0x01, + #[eth] TransactionsPacket = 0x02, + #[eth] GetBlockHeadersPacket = 0x03, + #[eth] BlockHeadersPacket = 0x04, + #[eth] GetBlockBodiesPacket = 0x05, + #[eth] BlockBodiesPacket = 0x06, + #[eth] NewBlockPacket = 0x07, + + #[eth] GetNodeDataPacket = 0x0d, + #[eth] NodeDataPacket = 0x0e, + #[eth] GetReceiptsPacket = 0x0f, + #[eth] ReceiptsPacket = 0x10, + + #[par] GetSnapshotManifestPacket = 0x11, + #[par] SnapshotManifestPacket = 0x12, + #[par] GetSnapshotDataPacket = 0x13, + #[par] SnapshotDataPacket = 0x14, + #[par] ConsensusDataPacket = 0x15, + #[par] PrivateTransactionPacket = 0x16, + #[par] SignedPrivateTransactionPacket = 0x17, } -use self::SyncPacket::*; - -/// Provide both subprotocol and packet id information within the -/// same object. -pub trait PacketInfo { - fn id(&self) -> PacketId; - fn protocol(&self) -> ProtocolId; -} - -// The mechanism to match packet ids and protocol may be improved -// through some macro magic, but for now this works. -impl PacketInfo for SyncPacket { - fn protocol(&self) -> ProtocolId { - match self { - StatusPacket | - NewBlockHashesPacket | - TransactionsPacket | - GetBlockHeadersPacket | - BlockHeadersPacket | - GetBlockBodiesPacket | - BlockBodiesPacket | - NewBlockPacket | - - GetNodeDataPacket| - NodeDataPacket | - GetReceiptsPacket | - ReceiptsPacket - - => ETH_PROTOCOL, - - GetSnapshotManifestPacket| - SnapshotManifestPacket | - GetSnapshotDataPacket | - SnapshotDataPacket | - ConsensusDataPacket | - PrivateTransactionPacket | - SignedPrivateTransactionPacket - - => WARP_SYNC_PROTOCOL_ID, - } - } - - fn id(&self) -> PacketId { - (*self) as PacketId - } -} #[cfg(test)] mod tests { use super::*; - use enum_primitive::FromPrimitive; - #[test] fn packet_ids_from_u8_when_from_primitive_zero_then_equals_status_packet() { assert_eq!(SyncPacket::from_u8(0x00), Some(StatusPacket)); diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index 8a1e19569a4..4d3cb9ac509 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -44,8 +44,6 @@ extern crate ethcore_light as light; #[cfg(test)] extern crate kvdb_memorydb; #[cfg(test)] extern crate rustc_hex; -#[macro_use] -extern crate enum_primitive; #[macro_use] extern crate macros; #[macro_use] @@ -54,6 +52,8 @@ extern crate log; extern crate heapsize; #[macro_use] extern crate trace_time; +#[macro_use] +extern crate syncpacketid_derive; mod chain; mod blocks; diff --git a/util/syncpacketid_derive/Cargo.toml b/util/syncpacketid_derive/Cargo.toml new file mode 100644 index 00000000000..e14c2ca6137 --- /dev/null +++ b/util/syncpacketid_derive/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "syncpacketid_derive" +version = "0.1.0" +authors = ["Fernando Herrero Carrón "] + +[lib] +name = "syncpacketid_derive" +proc-macro = true + +[dependencies] +syn = "0.15" +quote = "0.6" +proc-macro2 = "0.4" diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs new file mode 100644 index 00000000000..db91d5c3e47 --- /dev/null +++ b/util/syncpacketid_derive/src/lib.rs @@ -0,0 +1,69 @@ +#![recursion_limit="128"] + +extern crate proc_macro; +extern crate proc_macro2; +extern crate syn; +#[macro_use] +extern crate quote; + + + +use self::proc_macro::TokenStream; + +#[proc_macro_derive(SyncPackets, attributes(eth, par))] +pub fn sync_packets(input: TokenStream) -> TokenStream { + let ast = syn::parse(input).unwrap(); + let gen = impl_sync_packets(&ast); + gen.into() +} + + +fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { + let body = match ast.data { + syn::Data::Enum(ref e) => e, + _ => panic!("#[derive(RlpEncodable)] is only defined for enums."), + }; + + let eths: Vec<_> = body.variants.iter().filter(|v| v.attrs[0].path.is_ident("eth")).map(|v| &v.ident).collect(); + let pars: Vec<_> = body.variants.iter().filter(|v| v.attrs[0].path.is_ident("par")).map(|v| &v.ident).collect(); + + let idents: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); + let values: Vec<_> = body.variants.iter().map(|v| v.discriminant.clone().unwrap().1).collect(); + + quote!{ + impl SyncPacket { + pub fn from_u8(id: u8) -> Option { + match id { + #(#values => Some(#idents)),*, + _ => None + + } + } + } + + use self::SyncPacket::*; + + /// Provide both subprotocol and packet id information within the + /// same object. + pub trait PacketInfo { + fn id(&self) -> PacketId; + fn protocol(&self) -> ProtocolId; + } + + // The mechanism to match packet ids and protocol may be improved + // through some macro magic, but for now this works. + impl PacketInfo for SyncPacket { + fn protocol(&self) -> ProtocolId { + match self { + #(#eths)|* => ETH_PROTOCOL, + #(#pars)|* => WARP_SYNC_PROTOCOL_ID, + } + } + + fn id(&self) -> PacketId { + (*self) as PacketId + } + } + + } +} From 64b2d6b8dad8bbf5746af313bafbbd98537b44f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Tue, 12 Feb 2019 14:00:39 +0100 Subject: [PATCH 02/16] Minor fixes. --- ethcore/sync/src/chain/sync_packet.rs | 61 ++++++++++++++++++--------- util/syncpacketid_derive/src/lib.rs | 17 +++++--- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index 18fe84201d7..826b85ddc08 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -35,27 +35,46 @@ use network::{PacketId, ProtocolId}; /// packet id clashes when defining new ids. #[derive(Clone, Copy, Debug, SyncPackets, PartialEq)] pub enum SyncPacket { - #[eth] StatusPacket = 0x00, - #[eth] NewBlockHashesPacket = 0x01, - #[eth] TransactionsPacket = 0x02, - #[eth] GetBlockHeadersPacket = 0x03, - #[eth] BlockHeadersPacket = 0x04, - #[eth] GetBlockBodiesPacket = 0x05, - #[eth] BlockBodiesPacket = 0x06, - #[eth] NewBlockPacket = 0x07, - - #[eth] GetNodeDataPacket = 0x0d, - #[eth] NodeDataPacket = 0x0e, - #[eth] GetReceiptsPacket = 0x0f, - #[eth] ReceiptsPacket = 0x10, - - #[par] GetSnapshotManifestPacket = 0x11, - #[par] SnapshotManifestPacket = 0x12, - #[par] GetSnapshotDataPacket = 0x13, - #[par] SnapshotDataPacket = 0x14, - #[par] ConsensusDataPacket = 0x15, - #[par] PrivateTransactionPacket = 0x16, - #[par] SignedPrivateTransactionPacket = 0x17, + #[eth] + StatusPacket = 0x00, + #[eth] + NewBlockHashesPacket = 0x01, + #[eth] + TransactionsPacket = 0x02, + #[eth] + GetBlockHeadersPacket = 0x03, + #[eth] + BlockHeadersPacket = 0x04, + #[eth] + GetBlockBodiesPacket = 0x05, + #[eth] + BlockBodiesPacket = 0x06, + #[eth] + NewBlockPacket = 0x07, + + #[eth] + GetNodeDataPacket = 0x0d, + #[eth] + NodeDataPacket = 0x0e, + #[eth] + GetReceiptsPacket = 0x0f, + #[eth] + ReceiptsPacket = 0x10, + + #[par] + GetSnapshotManifestPacket = 0x11, + #[par] + SnapshotManifestPacket = 0x12, + #[par] + GetSnapshotDataPacket = 0x13, + #[par] + SnapshotDataPacket = 0x14, + #[par] + ConsensusDataPacket = 0x15, + #[par] + PrivateTransactionPacket = 0x16, + #[par] + SignedPrivateTransactionPacket = 0x17, } diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index db91d5c3e47..14e9a9f264f 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -10,6 +10,13 @@ extern crate quote; use self::proc_macro::TokenStream; +/// The SyncPackets derive-macro will provide an enum with this attribute: +/// +/// * With a method "from_u8" which will optionally convert a u8 value to +/// one of the variants or None if the value is unknown. +/// +/// * With an implementation of a trait PacketInfo to get the packet id and +/// the protocol from instances of the enum. #[proc_macro_derive(SyncPackets, attributes(eth, par))] pub fn sync_packets(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); @@ -21,9 +28,11 @@ pub fn sync_packets(input: TokenStream) -> TokenStream { fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let body = match ast.data { syn::Data::Enum(ref e) => e, - _ => panic!("#[derive(RlpEncodable)] is only defined for enums."), + _ => panic!("#[derive(SyncPackets)] is only defined for enums."), }; + let enum_name = &ast.ident; + let eths: Vec<_> = body.variants.iter().filter(|v| v.attrs[0].path.is_ident("eth")).map(|v| &v.ident).collect(); let pars: Vec<_> = body.variants.iter().filter(|v| v.attrs[0].path.is_ident("par")).map(|v| &v.ident).collect(); @@ -31,7 +40,7 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let values: Vec<_> = body.variants.iter().map(|v| v.discriminant.clone().unwrap().1).collect(); quote!{ - impl SyncPacket { + impl #enum_name { pub fn from_u8(id: u8) -> Option { match id { #(#values => Some(#idents)),*, @@ -50,9 +59,7 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { fn protocol(&self) -> ProtocolId; } - // The mechanism to match packet ids and protocol may be improved - // through some macro magic, but for now this works. - impl PacketInfo for SyncPacket { + impl PacketInfo for #enum_name { fn protocol(&self) -> ProtocolId { match self { #(#eths)|* => ETH_PROTOCOL, From e2a870917a2a413e28a633d4e8ea5a1feafcf68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Tue, 12 Feb 2019 16:36:21 +0100 Subject: [PATCH 03/16] Reformat --- ethcore/sync/src/chain/sync_packet.rs | 67 +++++++++------------------ util/syncpacketid_derive/src/lib.rs | 13 +++--- 2 files changed, 29 insertions(+), 51 deletions(-) diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index 826b85ddc08..c42466d5be9 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -22,8 +22,6 @@ //! to convert to/from the packet id values transmitted over the //! wire. - - use api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; use network::{PacketId, ProtocolId}; @@ -33,52 +31,31 @@ use network::{PacketId, ProtocolId}; /// to enum variants. This implicitly provides a mechanism to /// check whether a given packet id is known, and to prevent /// packet id clashes when defining new ids. -#[derive(Clone, Copy, Debug, SyncPackets, PartialEq)] +#[derive(SyncPackets, Clone, Copy, Debug, PartialEq)] pub enum SyncPacket { - #[eth] - StatusPacket = 0x00, - #[eth] - NewBlockHashesPacket = 0x01, - #[eth] - TransactionsPacket = 0x02, - #[eth] - GetBlockHeadersPacket = 0x03, - #[eth] - BlockHeadersPacket = 0x04, - #[eth] - GetBlockBodiesPacket = 0x05, - #[eth] - BlockBodiesPacket = 0x06, - #[eth] - NewBlockPacket = 0x07, - - #[eth] - GetNodeDataPacket = 0x0d, - #[eth] - NodeDataPacket = 0x0e, - #[eth] - GetReceiptsPacket = 0x0f, - #[eth] - ReceiptsPacket = 0x10, - - #[par] - GetSnapshotManifestPacket = 0x11, - #[par] - SnapshotManifestPacket = 0x12, - #[par] - GetSnapshotDataPacket = 0x13, - #[par] - SnapshotDataPacket = 0x14, - #[par] - ConsensusDataPacket = 0x15, - #[par] - PrivateTransactionPacket = 0x16, - #[par] - SignedPrivateTransactionPacket = 0x17, + #[eth] StatusPacket = 0x00, + #[eth] NewBlockHashesPacket = 0x01, + #[eth] TransactionsPacket = 0x02, + #[eth] GetBlockHeadersPacket = 0x03, + #[eth] BlockHeadersPacket = 0x04, + #[eth] GetBlockBodiesPacket = 0x05, + #[eth] BlockBodiesPacket = 0x06, + #[eth] NewBlockPacket = 0x07, + + #[eth] GetNodeDataPacket = 0x0d, + #[eth] NodeDataPacket = 0x0e, + #[eth] GetReceiptsPacket = 0x0f, + #[eth] ReceiptsPacket = 0x10, + + #[par] GetSnapshotManifestPacket = 0x11, + #[par] SnapshotManifestPacket = 0x12, + #[par] GetSnapshotDataPacket = 0x13, + #[par] SnapshotDataPacket = 0x14, + #[par] ConsensusDataPacket = 0x15, + #[par] PrivateTransactionPacket = 0x16, + #[par] SignedPrivateTransactionPacket = 0x17, } - - #[cfg(test)] mod tests { use super::*; diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index 14e9a9f264f..5dbdd882299 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -6,8 +6,6 @@ extern crate syn; #[macro_use] extern crate quote; - - use self::proc_macro::TokenStream; /// The SyncPackets derive-macro will provide an enum with this attribute: @@ -24,7 +22,6 @@ pub fn sync_packets(input: TokenStream) -> TokenStream { gen.into() } - fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let body = match ast.data { syn::Data::Enum(ref e) => e, @@ -33,8 +30,13 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let enum_name = &ast.ident; - let eths: Vec<_> = body.variants.iter().filter(|v| v.attrs[0].path.is_ident("eth")).map(|v| &v.ident).collect(); - let pars: Vec<_> = body.variants.iter().filter(|v| v.attrs[0].path.is_ident("par")).map(|v| &v.ident).collect(); + let eths: Vec<_> = body.variants.iter() + .filter(|v| v.attrs[0].path.is_ident("eth")) + .map(|v| &v.ident).collect(); + + let pars: Vec<_> = body.variants.iter() + .filter(|v| v.attrs[0].path.is_ident("par")) + .map(|v| &v.ident).collect(); let idents: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); let values: Vec<_> = body.variants.iter().map(|v| v.discriminant.clone().unwrap().1).collect(); @@ -71,6 +73,5 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { (*self) as PacketId } } - } } From f49ad6943c97217700ce724289d22a96f5431512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Wed, 13 Feb 2019 11:04:55 +0100 Subject: [PATCH 04/16] Move "use"s to where they are actually used --- ethcore/sync/src/chain/sync_packet.rs | 3 --- util/syncpacketid_derive/src/lib.rs | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index c42466d5be9..141b29b6241 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -22,9 +22,6 @@ //! to convert to/from the packet id values transmitted over the //! wire. -use api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; -use network::{PacketId, ProtocolId}; - /// An enum that defines all known packet ids in the context of /// synchronization and provides a mechanism to convert from /// packet ids (of type PacketId or u8) directly read from the network diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index 5dbdd882299..e569f348e07 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -42,6 +42,9 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let values: Vec<_> = body.variants.iter().map(|v| v.discriminant.clone().unwrap().1).collect(); quote!{ + use api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; + use network::{PacketId, ProtocolId}; + impl #enum_name { pub fn from_u8(id: u8) -> Option { match id { From c0bc23d55587b3becfb87bfd8f1201f142f42465 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 13 Feb 2019 16:26:46 +0100 Subject: [PATCH 05/16] Update util/syncpacketid_derive/src/lib.rs Co-Authored-By: elferdo --- util/syncpacketid_derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index e569f348e07..9e0b9f3f062 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -31,7 +31,7 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let enum_name = &ast.ident; let eths: Vec<_> = body.variants.iter() - .filter(|v| v.attrs[0].path.is_ident("eth")) + .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]).path.is_ident("eth")) .map(|v| &v.ident).collect(); let pars: Vec<_> = body.variants.iter() From 9780b0ad258b87cda272e1c6558b87a0aff82539 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 13 Feb 2019 16:26:55 +0100 Subject: [PATCH 06/16] Update util/syncpacketid_derive/src/lib.rs Co-Authored-By: elferdo --- util/syncpacketid_derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index 9e0b9f3f062..0f47d735ae8 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -35,7 +35,7 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { .map(|v| &v.ident).collect(); let pars: Vec<_> = body.variants.iter() - .filter(|v| v.attrs[0].path.is_ident("par")) + .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]).path.is_ident("par"))) .map(|v| &v.ident).collect(); let idents: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); From 2518d1cf14189b8e6806b6b39b86bd58e40d1dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Thu, 14 Feb 2019 10:32:31 +0100 Subject: [PATCH 07/16] Make syncpacketid_derive rust 2018 --- ethcore/sync/src/chain/sync_packet.rs | 2 ++ ethcore/sync/src/lib.rs | 3 +-- util/syncpacketid_derive/Cargo.toml | 1 + util/syncpacketid_derive/src/lib.rs | 15 +++++++-------- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index 141b29b6241..e6bff43d32b 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -22,6 +22,8 @@ //! to convert to/from the packet id values transmitted over the //! wire. +use syncpacketid_derive::SyncPackets; + /// An enum that defines all known packet ids in the context of /// synchronization and provides a mechanism to convert from /// packet ids (of type PacketId or u8) directly read from the network diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index 4d3cb9ac509..3302e12f697 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -35,6 +35,7 @@ extern crate parity_bytes as bytes; extern crate parking_lot; extern crate rand; extern crate rlp; +extern crate syncpacketid_derive; extern crate triehash_ethereum; extern crate ethcore_light as light; @@ -52,8 +53,6 @@ extern crate log; extern crate heapsize; #[macro_use] extern crate trace_time; -#[macro_use] -extern crate syncpacketid_derive; mod chain; mod blocks; diff --git a/util/syncpacketid_derive/Cargo.toml b/util/syncpacketid_derive/Cargo.toml index e14c2ca6137..f391c301487 100644 --- a/util/syncpacketid_derive/Cargo.toml +++ b/util/syncpacketid_derive/Cargo.toml @@ -2,6 +2,7 @@ name = "syncpacketid_derive" version = "0.1.0" authors = ["Fernando Herrero Carrón "] +edition = "2018" [lib] name = "syncpacketid_derive" diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index 0f47d735ae8..5ad568ee1ce 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -1,12 +1,11 @@ #![recursion_limit="128"] +// Needs to be "extern crate" even in rust 2018: +// https://blog.rust-lang.org/2018/12/21/Procedural-Macros-in-Rust-2018.html extern crate proc_macro; -extern crate proc_macro2; -extern crate syn; -#[macro_use] -extern crate quote; -use self::proc_macro::TokenStream; +use proc_macro::TokenStream; +use quote::quote; /// The SyncPackets derive-macro will provide an enum with this attribute: /// @@ -31,18 +30,18 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let enum_name = &ast.ident; let eths: Vec<_> = body.variants.iter() - .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]).path.is_ident("eth")) + .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]").path.is_ident("eth")) .map(|v| &v.ident).collect(); let pars: Vec<_> = body.variants.iter() - .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]).path.is_ident("par"))) + .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]").path.is_ident("par")) .map(|v| &v.ident).collect(); let idents: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); let values: Vec<_> = body.variants.iter().map(|v| v.discriminant.clone().unwrap().1).collect(); quote!{ - use api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; + use crate::api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; use network::{PacketId, ProtocolId}; impl #enum_name { From 9e2c84b5161ae7376887457fce1eb00ad7f3da7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Thu, 14 Feb 2019 10:37:06 +0100 Subject: [PATCH 08/16] Replace unwrap with expect --- util/syncpacketid_derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index 5ad568ee1ce..f06ebba914f 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -38,7 +38,7 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { .map(|v| &v.ident).collect(); let idents: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); - let values: Vec<_> = body.variants.iter().map(|v| v.discriminant.clone().unwrap().1).collect(); + let values: Vec<_> = body.variants.iter().map(|v| v.discriminant.clone().expect("enum pattern is not discriminant; should have assigned unique value such as #[eth] Foo = 1").1).collect(); quote!{ use crate::api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; From aba3527fc12f8c7de6e2eb95d21318badf085335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Thu, 14 Feb 2019 12:57:53 +0100 Subject: [PATCH 09/16] Replace concrete protocol specifications with a "protocol" attribute --- ethcore/sync/src/chain/sync_packet.rs | 39 ++++++++++++++------------- util/syncpacketid_derive/src/lib.rs | 35 +++++++++++++++--------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index e6bff43d32b..295ef1a002c 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -23,6 +23,7 @@ //! wire. use syncpacketid_derive::SyncPackets; +use crate::api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; /// An enum that defines all known packet ids in the context of /// synchronization and provides a mechanism to convert from @@ -32,27 +33,27 @@ use syncpacketid_derive::SyncPackets; /// packet id clashes when defining new ids. #[derive(SyncPackets, Clone, Copy, Debug, PartialEq)] pub enum SyncPacket { - #[eth] StatusPacket = 0x00, - #[eth] NewBlockHashesPacket = 0x01, - #[eth] TransactionsPacket = 0x02, - #[eth] GetBlockHeadersPacket = 0x03, - #[eth] BlockHeadersPacket = 0x04, - #[eth] GetBlockBodiesPacket = 0x05, - #[eth] BlockBodiesPacket = 0x06, - #[eth] NewBlockPacket = 0x07, + #[protocol(ETH_PROTOCOL)] StatusPacket = 0x00, + #[protocol(ETH_PROTOCOL)] NewBlockHashesPacket = 0x01, + #[protocol(ETH_PROTOCOL)] TransactionsPacket = 0x02, + #[protocol(ETH_PROTOCOL)] GetBlockHeadersPacket = 0x03, + #[protocol(ETH_PROTOCOL)] BlockHeadersPacket = 0x04, + #[protocol(ETH_PROTOCOL)] GetBlockBodiesPacket = 0x05, + #[protocol(ETH_PROTOCOL)] BlockBodiesPacket = 0x06, + #[protocol(ETH_PROTOCOL)] NewBlockPacket = 0x07, - #[eth] GetNodeDataPacket = 0x0d, - #[eth] NodeDataPacket = 0x0e, - #[eth] GetReceiptsPacket = 0x0f, - #[eth] ReceiptsPacket = 0x10, + #[protocol(ETH_PROTOCOL)] GetNodeDataPacket = 0x0d, + #[protocol(ETH_PROTOCOL)] NodeDataPacket = 0x0e, + #[protocol(ETH_PROTOCOL)] GetReceiptsPacket = 0x0f, + #[protocol(ETH_PROTOCOL)] ReceiptsPacket = 0x10, - #[par] GetSnapshotManifestPacket = 0x11, - #[par] SnapshotManifestPacket = 0x12, - #[par] GetSnapshotDataPacket = 0x13, - #[par] SnapshotDataPacket = 0x14, - #[par] ConsensusDataPacket = 0x15, - #[par] PrivateTransactionPacket = 0x16, - #[par] SignedPrivateTransactionPacket = 0x17, + #[protocol(WARP_SYNC_PROTOCOL_ID)] GetSnapshotManifestPacket = 0x11, + #[protocol(WARP_SYNC_PROTOCOL_ID)] SnapshotManifestPacket = 0x12, + #[protocol(WARP_SYNC_PROTOCOL_ID)] GetSnapshotDataPacket = 0x13, + #[protocol(WARP_SYNC_PROTOCOL_ID)] SnapshotDataPacket = 0x14, + #[protocol(WARP_SYNC_PROTOCOL_ID)] ConsensusDataPacket = 0x15, + #[protocol(WARP_SYNC_PROTOCOL_ID)] PrivateTransactionPacket = 0x16, + #[protocol(WARP_SYNC_PROTOCOL_ID)] SignedPrivateTransactionPacket = 0x17, } #[cfg(test)] diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index f06ebba914f..82a2cc5dfec 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -14,13 +14,28 @@ use quote::quote; /// /// * With an implementation of a trait PacketInfo to get the packet id and /// the protocol from instances of the enum. -#[proc_macro_derive(SyncPackets, attributes(eth, par))] +#[proc_macro_derive(SyncPackets, attributes(protocol))] pub fn sync_packets(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); let gen = impl_sync_packets(&ast); gen.into() } +fn parse_protocol_attribute(input: proc_macro2::TokenStream) -> proc_macro2::Ident { + let groups: Vec<_> = input.into_iter().take(1).collect(); + + let group: Vec<_> = match &groups[0] { + proc_macro2::TokenTree::Group(g) => g.stream().into_iter().take(1).collect(), + _ => panic!() + }; + + if let proc_macro2::TokenTree::Ident(ref i) = group[0] { + proc_macro2::Ident::new(i.to_string().as_ref(), i.span()) + } else { + panic!("Should be an Ident"); + } +} + fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let body = match ast.data { syn::Data::Enum(ref e) => e, @@ -29,25 +44,22 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let enum_name = &ast.ident; - let eths: Vec<_> = body.variants.iter() - .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]").path.is_ident("eth")) - .map(|v| &v.ident).collect(); + let idents1: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); + let idents2 = idents1.clone(); - let pars: Vec<_> = body.variants.iter() - .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]").path.is_ident("par")) - .map(|v| &v.ident).collect(); + let prots:Vec<_> = body.variants.iter() + .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]").path.is_ident("protocol")) + .map(|v| parse_protocol_attribute(v.attrs.get(0).unwrap().tts.clone())).collect(); - let idents: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); let values: Vec<_> = body.variants.iter().map(|v| v.discriminant.clone().expect("enum pattern is not discriminant; should have assigned unique value such as #[eth] Foo = 1").1).collect(); quote!{ - use crate::api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; use network::{PacketId, ProtocolId}; impl #enum_name { pub fn from_u8(id: u8) -> Option { match id { - #(#values => Some(#idents)),*, + #(#values => Some(#idents1)),*, _ => None } @@ -66,8 +78,7 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { impl PacketInfo for #enum_name { fn protocol(&self) -> ProtocolId { match self { - #(#eths)|* => ETH_PROTOCOL, - #(#pars)|* => WARP_SYNC_PROTOCOL_ID, + #(#idents2 => #prots),* } } From 03b74320631d5c7c684001e17b44f855c9a677d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Fri, 15 Feb 2019 09:34:59 +0100 Subject: [PATCH 10/16] Parse "protocol" attribute arguments --- util/syncpacketid_derive/src/lib.rs | 87 ++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index 82a2cc5dfec..c6efc8707cb 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -7,6 +7,33 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; +fn parse_protocol_arguments(args: syn::MetaList) -> proc_macro2::Ident { + if args.nested.len() != 1 { + panic!("protocol attribute should have exactly one argument"); + } + + match args.nested.first().expect("protocol attribute without value").value() { + // Meta argument + syn::NestedMeta::Meta(meta) => match meta { + syn::Meta::Word(ident) => ident.clone(), + _ => panic!("nested arguments to protocol are not allowed"), + }, + // Quoted string + _ => panic!("protocol argument must be an unquoted identifier") + } +} + +/// Helper function to parse arguments to the protocol attribute. +/// Syntax should be #[protocol(P)] PacketName = 0xNN, +fn parse_protocol_attribute(input: syn::Meta) -> proc_macro2::Ident { + // Arguments to invocation attributes are delivered as a list + match input { + syn::Meta::Word(_) => panic!("protocol attribute without argument"), + syn::Meta::List(args) => parse_protocol_arguments(args), + _ => panic!("unsupported syntax") + } +} + /// The SyncPackets derive-macro will provide an enum with this attribute: /// /// * With a method "from_u8" which will optionally convert a u8 value to @@ -16,26 +43,11 @@ use quote::quote; /// the protocol from instances of the enum. #[proc_macro_derive(SyncPackets, attributes(protocol))] pub fn sync_packets(input: TokenStream) -> TokenStream { - let ast = syn::parse(input).unwrap(); + let ast = syn::parse(input).expect("invalid enum syntax"); let gen = impl_sync_packets(&ast); gen.into() } -fn parse_protocol_attribute(input: proc_macro2::TokenStream) -> proc_macro2::Ident { - let groups: Vec<_> = input.into_iter().take(1).collect(); - - let group: Vec<_> = match &groups[0] { - proc_macro2::TokenTree::Group(g) => g.stream().into_iter().take(1).collect(), - _ => panic!() - }; - - if let proc_macro2::TokenTree::Ident(ref i) = group[0] { - proc_macro2::Ident::new(i.to_string().as_ref(), i.span()) - } else { - panic!("Should be an Ident"); - } -} - fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let body = match ast.data { syn::Data::Enum(ref e) => e, @@ -44,14 +56,39 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let enum_name = &ast.ident; - let idents1: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); - let idents2 = idents1.clone(); - - let prots:Vec<_> = body.variants.iter() - .filter(|v| v.attrs.get(0).expect("attribute is missing; annotate your enum patterns with #[eth] or #[par]").path.is_ident("protocol")) - .map(|v| parse_protocol_attribute(v.attrs.get(0).unwrap().tts.clone())).collect(); + if body.variants.is_empty() { + panic!("enum {} has no variants defined", enum_name); + } - let values: Vec<_> = body.variants.iter().map(|v| v.discriminant.clone().expect("enum pattern is not discriminant; should have assigned unique value such as #[eth] Foo = 1").1).collect(); + // Apparently quote! consumes interpolated variables. Clone ids + // to use them twice. + let idents_from_u8: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); + let idents_enum = idents_from_u8.clone(); + + // Within each variant of the enum find the first "protocol" attribute + // and extract its argument + let protocols:Vec<_> = body.variants.iter() + .filter_map( + |v| v.attrs + .iter() + .find(|&x| x.path.is_ident("protocol")) + .or_else(|| panic!("enum variant without protocol attribute in {}", &enum_name)) + ).map(|a| parse_protocol_attribute(a + .parse_meta() + .clone() + .expect("unknown arguments passed to protocol")) + ).collect(); + + + // Values asigned to the variants in the enum + let values: Vec<_> = body.variants.iter() + .map( + |v| v.discriminant + .clone() + .expect("enum pattern is not discriminant; should have assigned unique value such as Foo = 1") + .1 + ) + .collect(); quote!{ use network::{PacketId, ProtocolId}; @@ -59,7 +96,7 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { impl #enum_name { pub fn from_u8(id: u8) -> Option { match id { - #(#values => Some(#idents1)),*, + #(#values => Some(#idents_from_u8)),*, _ => None } @@ -78,7 +115,7 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { impl PacketInfo for #enum_name { fn protocol(&self) -> ProtocolId { match self { - #(#idents2 => #prots),* + #(#idents_enum => #protocols),* } } From 9ec2b7fa19c053e19cb0ddfb4b1918e4911f6a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Fri, 15 Feb 2019 11:19:58 +0100 Subject: [PATCH 11/16] Reduce qualification --- util/syncpacketid_derive/src/lib.rs | 39 +++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacketid_derive/src/lib.rs index c6efc8707cb..a28b45b2294 100644 --- a/util/syncpacketid_derive/src/lib.rs +++ b/util/syncpacketid_derive/src/lib.rs @@ -1,21 +1,38 @@ +// Copyright 2015-2019 Parity Technologies (UK) Ltd. +// This file is part of Parity Ethereum. + +// Parity Ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Ethereum. If not, see . + #![recursion_limit="128"] // Needs to be "extern crate" even in rust 2018: // https://blog.rust-lang.org/2018/12/21/Procedural-Macros-in-Rust-2018.html extern crate proc_macro; -use proc_macro::TokenStream; +use proc_macro2::Ident; use quote::quote; +use syn::{Data, DeriveInput, Meta, MetaList, NestedMeta}; -fn parse_protocol_arguments(args: syn::MetaList) -> proc_macro2::Ident { +fn parse_protocol_arguments(args: MetaList) -> Ident { if args.nested.len() != 1 { panic!("protocol attribute should have exactly one argument"); } match args.nested.first().expect("protocol attribute without value").value() { // Meta argument - syn::NestedMeta::Meta(meta) => match meta { - syn::Meta::Word(ident) => ident.clone(), + NestedMeta::Meta(meta) => match meta { + Meta::Word(ident) => ident.clone(), _ => panic!("nested arguments to protocol are not allowed"), }, // Quoted string @@ -25,11 +42,11 @@ fn parse_protocol_arguments(args: syn::MetaList) -> proc_macro2::Ident { /// Helper function to parse arguments to the protocol attribute. /// Syntax should be #[protocol(P)] PacketName = 0xNN, -fn parse_protocol_attribute(input: syn::Meta) -> proc_macro2::Ident { +fn parse_protocol_attribute(input: Meta) -> Ident { // Arguments to invocation attributes are delivered as a list match input { - syn::Meta::Word(_) => panic!("protocol attribute without argument"), - syn::Meta::List(args) => parse_protocol_arguments(args), + Meta::Word(_) => panic!("protocol attribute without argument"), + Meta::List(args) => parse_protocol_arguments(args), _ => panic!("unsupported syntax") } } @@ -42,15 +59,15 @@ fn parse_protocol_attribute(input: syn::Meta) -> proc_macro2::Ident { /// * With an implementation of a trait PacketInfo to get the packet id and /// the protocol from instances of the enum. #[proc_macro_derive(SyncPackets, attributes(protocol))] -pub fn sync_packets(input: TokenStream) -> TokenStream { +pub fn sync_packets(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).expect("invalid enum syntax"); let gen = impl_sync_packets(&ast); gen.into() } -fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { +fn impl_sync_packets(ast: &DeriveInput) -> proc_macro2::TokenStream { let body = match ast.data { - syn::Data::Enum(ref e) => e, + Data::Enum(ref e) => e, _ => panic!("#[derive(SyncPackets)] is only defined for enums."), }; @@ -85,7 +102,7 @@ fn impl_sync_packets(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { .map( |v| v.discriminant .clone() - .expect("enum pattern is not discriminant; should have assigned unique value such as Foo = 1") + .expect("enum pattern is not discriminant; should have assigned a unique value such as Foo = 1") .1 ) .collect(); From 311b73598d726bcb30b9afd40f464e725c72b0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Wed, 20 Feb 2019 16:21:04 +0100 Subject: [PATCH 12/16] Rename syncpacketid_derive to syncpacket --- Cargo.lock | 4 ++-- ethcore/sync/Cargo.toml | 2 +- ethcore/sync/src/chain/sync_packet.rs | 2 +- ethcore/sync/src/lib.rs | 2 +- util/{syncpacketid_derive => syncpacket}/Cargo.toml | 4 ++-- util/{syncpacketid_derive => syncpacket}/src/lib.rs | 0 6 files changed, 7 insertions(+), 7 deletions(-) rename util/{syncpacketid_derive => syncpacket}/Cargo.toml (76%) rename util/{syncpacketid_derive => syncpacket}/src/lib.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index a1658410994..42e833606d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1132,7 +1132,7 @@ dependencies = [ "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syncpacketid_derive 0.1.0", + "syncpacket 0.1.0", "trace-time 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "triehash-ethereum 0.2.0", ] @@ -3657,7 +3657,7 @@ dependencies = [ ] [[package]] -name = "syncpacketid_derive" +name = "syncpacket" version = "0.1.0" dependencies = [ "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index 63da1924225..fa33c6a033a 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -29,7 +29,7 @@ parity-bytes = "0.1" parking_lot = "0.7" rand = "0.4" rlp = { version = "0.3.0", features = ["ethereum"] } -syncpacketid_derive = { path = "../../util/syncpacketid_derive" } +syncpacket = { path = "../../util/syncpacket" } trace-time = "0.1" triehash-ethereum = {version = "0.2", path = "../../util/triehash-ethereum" } diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index 295ef1a002c..2131476a714 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -22,7 +22,7 @@ //! to convert to/from the packet id values transmitted over the //! wire. -use syncpacketid_derive::SyncPackets; +use syncpacket::SyncPackets; use crate::api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; /// An enum that defines all known packet ids in the context of diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index 3302e12f697..9ce5c93bf41 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -35,7 +35,7 @@ extern crate parity_bytes as bytes; extern crate parking_lot; extern crate rand; extern crate rlp; -extern crate syncpacketid_derive; +extern crate syncpacket; extern crate triehash_ethereum; extern crate ethcore_light as light; diff --git a/util/syncpacketid_derive/Cargo.toml b/util/syncpacket/Cargo.toml similarity index 76% rename from util/syncpacketid_derive/Cargo.toml rename to util/syncpacket/Cargo.toml index f391c301487..27609814670 100644 --- a/util/syncpacketid_derive/Cargo.toml +++ b/util/syncpacket/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "syncpacketid_derive" +name = "syncpacket" version = "0.1.0" authors = ["Fernando Herrero Carrón "] edition = "2018" [lib] -name = "syncpacketid_derive" +name = "syncpacket" proc-macro = true [dependencies] diff --git a/util/syncpacketid_derive/src/lib.rs b/util/syncpacket/src/lib.rs similarity index 100% rename from util/syncpacketid_derive/src/lib.rs rename to util/syncpacket/src/lib.rs From 7c638a4e219b87637e3a00a7ac89bfd9f7922765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Thu, 21 Feb 2019 11:38:15 +0100 Subject: [PATCH 13/16] Change owner --- util/syncpacket/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/syncpacket/Cargo.toml b/util/syncpacket/Cargo.toml index 27609814670..d9c70a005c1 100644 --- a/util/syncpacket/Cargo.toml +++ b/util/syncpacket/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "syncpacket" version = "0.1.0" -authors = ["Fernando Herrero Carrón "] +authors = ["Parity Technologies "] edition = "2018" [lib] From 702ebfb38a7bba3bf947386391023d0fbb76b91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Thu, 21 Feb 2019 11:38:28 +0100 Subject: [PATCH 14/16] Turn panics in macro into compiler errors --- ethcore/sync/src/chain/sync_packet.rs | 2 +- util/syncpacket/src/lib.rs | 118 ++++++++++++++------------ 2 files changed, 67 insertions(+), 53 deletions(-) diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index 2131476a714..984fb704816 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -33,7 +33,7 @@ use crate::api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; /// packet id clashes when defining new ids. #[derive(SyncPackets, Clone, Copy, Debug, PartialEq)] pub enum SyncPacket { - #[protocol(ETH_PROTOCOL)] StatusPacket = 0x00, + #[protocol(ETH_PROTOCOL)] StatusPacket = 0x00, #[protocol(ETH_PROTOCOL)] NewBlockHashesPacket = 0x01, #[protocol(ETH_PROTOCOL)] TransactionsPacket = 0x02, #[protocol(ETH_PROTOCOL)] GetBlockHeadersPacket = 0x03, diff --git a/util/syncpacket/src/lib.rs b/util/syncpacket/src/lib.rs index a28b45b2294..cdadd1626ff 100644 --- a/util/syncpacket/src/lib.rs +++ b/util/syncpacket/src/lib.rs @@ -22,32 +22,38 @@ extern crate proc_macro; use proc_macro2::Ident; use quote::quote; -use syn::{Data, DeriveInput, Meta, MetaList, NestedMeta}; +use syn::{Attribute, Data, DeriveInput, Meta, MetaList, NestedMeta, Result}; -fn parse_protocol_arguments(args: MetaList) -> Ident { +fn parse_protocol_arguments(args: &MetaList) -> Result<&Ident> { if args.nested.len() != 1 { - panic!("protocol attribute should have exactly one argument"); + return Err(syn::Error::new_spanned(args, "protocol attribute should have exactly one argument")); } + // We have exactly one argument, should not panic match args.nested.first().expect("protocol attribute without value").value() { // Meta argument NestedMeta::Meta(meta) => match meta { - Meta::Word(ident) => ident.clone(), - _ => panic!("nested arguments to protocol are not allowed"), + Meta::Word(ident) => Ok(&ident), + _ => return Err(syn::Error::new_spanned(meta, "nested arguments to protocol are not allowed")), }, // Quoted string - _ => panic!("protocol argument must be an unquoted identifier") + a @ _ => return Err(syn::Error::new_spanned(a, "protocol argument must be an unquoted identifier")) } } /// Helper function to parse arguments to the protocol attribute. /// Syntax should be #[protocol(P)] PacketName = 0xNN, -fn parse_protocol_attribute(input: Meta) -> Ident { +fn parse_protocol_attribute(input: &Attribute) -> Result { + let argument = match input.parse_meta() { + Ok(arg) => arg, + Err(err) => return Err(err) + }; + // Arguments to invocation attributes are delivered as a list - match input { - Meta::Word(_) => panic!("protocol attribute without argument"), - Meta::List(args) => parse_protocol_arguments(args), - _ => panic!("unsupported syntax") + match argument { + Meta::Word(_) => Err(syn::Error::new_spanned(input, "protocol attribute without argument")), + Meta::List(args) => parse_protocol_arguments(&args).map(|ok| ok.clone()), + _ => Err(syn::Error::new_spanned(input, "unsupported syntax")) } } @@ -60,21 +66,25 @@ fn parse_protocol_attribute(input: Meta) -> Ident { /// the protocol from instances of the enum. #[proc_macro_derive(SyncPackets, attributes(protocol))] pub fn sync_packets(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + // Can we ever panic here? let ast = syn::parse(input).expect("invalid enum syntax"); - let gen = impl_sync_packets(&ast); - gen.into() + + match impl_sync_packets(&ast) { + Ok(output) => output.into(), + Err(err) => err.to_compile_error().into(), + } } -fn impl_sync_packets(ast: &DeriveInput) -> proc_macro2::TokenStream { +fn impl_sync_packets(ast: &DeriveInput) -> Result { let body = match ast.data { Data::Enum(ref e) => e, - _ => panic!("#[derive(SyncPackets)] is only defined for enums."), + _ => return Err(syn::Error::new_spanned(ast, "#[derive(SyncPackets)] is only defined for enums.")), }; let enum_name = &ast.ident; if body.variants.is_empty() { - panic!("enum {} has no variants defined", enum_name); + return Err(syn::Error::new_spanned(enum_name, format!("enum {} has no variants defined", enum_name))); } // Apparently quote! consumes interpolated variables. Clone ids @@ -84,61 +94,65 @@ fn impl_sync_packets(ast: &DeriveInput) -> proc_macro2::TokenStream { // Within each variant of the enum find the first "protocol" attribute // and extract its argument - let protocols:Vec<_> = body.variants.iter() - .filter_map( + let protocols:Vec<_> = match body.variants.iter() + .map( |v| v.attrs .iter() .find(|&x| x.path.is_ident("protocol")) - .or_else(|| panic!("enum variant without protocol attribute in {}", &enum_name)) - ).map(|a| parse_protocol_attribute(a - .parse_meta() - .clone() - .expect("unknown arguments passed to protocol")) - ).collect(); + .ok_or(syn::Error::new_spanned(v, format!("enum variant without protocol attribute {}", &v.ident))) + .and_then(|ref a| parse_protocol_attribute(a)) + ).collect() { + Ok(v) => v, + Err(err) => return Err(err), + }; // Values asigned to the variants in the enum - let values: Vec<_> = body.variants.iter() + let values: Vec<_> = match body.variants.iter() .map( |v| v.discriminant - .clone() - .expect("enum pattern is not discriminant; should have assigned a unique value such as Foo = 1") - .1 + .as_ref() + .map(|d| &d.1) + .ok_or(syn::Error::new_spanned(v, "enum pattern is not discriminant; should have assigned a unique value such as Foo = 1")) ) - .collect(); + .collect() { + Ok(v) => v, + Err(err) => return Err(err), + }; - quote!{ - use network::{PacketId, ProtocolId}; + Ok(quote!{ + use network::{PacketId, ProtocolId}; - impl #enum_name { - pub fn from_u8(id: u8) -> Option { - match id { - #(#values => Some(#idents_from_u8)),*, - _ => None + impl #enum_name { + pub fn from_u8(id: u8) -> Option { + match id { + #(#values => Some(#idents_from_u8)),*, + _ => None + } } } - } - use self::SyncPacket::*; + use self::SyncPacket::*; - /// Provide both subprotocol and packet id information within the - /// same object. - pub trait PacketInfo { - fn id(&self) -> PacketId; - fn protocol(&self) -> ProtocolId; - } + /// Provide both subprotocol and packet id information within the + /// same object. + pub trait PacketInfo { + fn id(&self) -> PacketId; + fn protocol(&self) -> ProtocolId; + } - impl PacketInfo for #enum_name { - fn protocol(&self) -> ProtocolId { - match self { - #(#idents_enum => #protocols),* + impl PacketInfo for #enum_name { + fn protocol(&self) -> ProtocolId { + match self { + #(#idents_enum => #protocols),* + } } - } - fn id(&self) -> PacketId { - (*self) as PacketId + fn id(&self) -> PacketId { + (*self) as PacketId + } } } - } + ) } From c453e6eb5fd773f965dd765ef25c2f413d1fdfa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Thu, 21 Feb 2019 12:57:21 +0100 Subject: [PATCH 15/16] Simplify error handling with '?' --- ethcore/sync/src/chain/sync_packet.rs | 3 +- util/syncpacket/src/lib.rs | 63 +++++++++++++++------------ 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index 984fb704816..78ea2a73a2b 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -31,9 +31,10 @@ use crate::api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; /// to enum variants. This implicitly provides a mechanism to /// check whether a given packet id is known, and to prevent /// packet id clashes when defining new ids. + #[derive(SyncPackets, Clone, Copy, Debug, PartialEq)] pub enum SyncPacket { - #[protocol(ETH_PROTOCOL)] StatusPacket = 0x00, + #[protocol(ETH_PROTOCOL)] StatusPacket = 0x00, #[protocol(ETH_PROTOCOL)] NewBlockHashesPacket = 0x01, #[protocol(ETH_PROTOCOL)] TransactionsPacket = 0x02, #[protocol(ETH_PROTOCOL)] GetBlockHeadersPacket = 0x03, diff --git a/util/syncpacket/src/lib.rs b/util/syncpacket/src/lib.rs index cdadd1626ff..3f49b6aec0d 100644 --- a/util/syncpacket/src/lib.rs +++ b/util/syncpacket/src/lib.rs @@ -22,8 +22,12 @@ extern crate proc_macro; use proc_macro2::Ident; use quote::quote; -use syn::{Attribute, Data, DeriveInput, Meta, MetaList, NestedMeta, Result}; +use syn::{Attribute, Data, DeriveInput, Expr, Meta, MetaList, NestedMeta, Result, Variant}; +use syn::punctuated::Punctuated; +use syn::token::Comma; +/// Given a list of arguments to the "protocol" attribute, check +/// that there is only one argument and return it fn parse_protocol_arguments(args: &MetaList) -> Result<&Ident> { if args.nested.len() != 1 { return Err(syn::Error::new_spanned(args, "protocol attribute should have exactly one argument")); @@ -57,6 +61,33 @@ fn parse_protocol_attribute(input: &Attribute) -> Result { } } +/// For each variant in the enum check that it has a "protocol" +/// attribute. If found, parse its arguments and return one +/// single protocol id. +fn get_variant_protocol_idents(variants: &Punctuated) -> Result> { + variants.iter() + .map( + |v| v.attrs + .iter() + .find(|&x| x.path.is_ident("protocol")) + .ok_or(syn::Error::new_spanned(v, format!("enum variant without protocol attribute {}", &v.ident))) + .and_then(|ref a| parse_protocol_attribute(a)) + ).collect() +} + +/// For each variant in the enum make sure it has a numeric value +/// assigned and return it +fn get_variant_values(variants: &Punctuated) -> Result> { + variants.iter() + .map( + |v| v.discriminant + .as_ref() + .map(|d| &d.1) + .ok_or(syn::Error::new_spanned(v, "enum pattern is not discriminant; should have assigned a unique value such as Foo = 1")) + ) + .collect() +} + /// The SyncPackets derive-macro will provide an enum with this attribute: /// /// * With a method "from_u8" which will optionally convert a u8 value to @@ -75,6 +106,7 @@ pub fn sync_packets(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } } +/// Actual implementation of the macro SyncPackets fn impl_sync_packets(ast: &DeriveInput) -> Result { let body = match ast.data { Data::Enum(ref e) => e, @@ -92,33 +124,8 @@ fn impl_sync_packets(ast: &DeriveInput) -> Result { let idents_from_u8: Vec<_> = body.variants.iter().map(|v| &v.ident).collect(); let idents_enum = idents_from_u8.clone(); - // Within each variant of the enum find the first "protocol" attribute - // and extract its argument - let protocols:Vec<_> = match body.variants.iter() - .map( - |v| v.attrs - .iter() - .find(|&x| x.path.is_ident("protocol")) - .ok_or(syn::Error::new_spanned(v, format!("enum variant without protocol attribute {}", &v.ident))) - .and_then(|ref a| parse_protocol_attribute(a)) - ).collect() { - Ok(v) => v, - Err(err) => return Err(err), - }; - - - // Values asigned to the variants in the enum - let values: Vec<_> = match body.variants.iter() - .map( - |v| v.discriminant - .as_ref() - .map(|d| &d.1) - .ok_or(syn::Error::new_spanned(v, "enum pattern is not discriminant; should have assigned a unique value such as Foo = 1")) - ) - .collect() { - Ok(v) => v, - Err(err) => return Err(err), - }; + let protocols = get_variant_protocol_idents(&body.variants)?; + let values = get_variant_values(&body.variants)?; Ok(quote!{ use network::{PacketId, ProtocolId}; From 8fe741f9414a1ab8b50bfeada41a4d6d96d321b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Herrero=20Carr=C3=B3n?= Date: Thu, 21 Feb 2019 14:05:29 +0100 Subject: [PATCH 16/16] Move tests from ethcore-sync to syncpacket --- Cargo.lock | 1 + ethcore/sync/src/chain/sync_packet.rs | 34 +----------------- util/syncpacket/Cargo.toml | 3 ++ util/syncpacket/src/lib.rs | 47 ++++++++++++------------ util/syncpacket/tests/syncpacket.rs | 51 +++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 57 deletions(-) create mode 100644 util/syncpacket/tests/syncpacket.rs diff --git a/Cargo.lock b/Cargo.lock index 42e833606d4..e6a90208b16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3660,6 +3660,7 @@ dependencies = [ name = "syncpacket" version = "0.1.0" dependencies = [ + "ethcore-network 1.12.0", "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/sync/src/chain/sync_packet.rs b/ethcore/sync/src/chain/sync_packet.rs index 78ea2a73a2b..69fb6e3578c 100644 --- a/ethcore/sync/src/chain/sync_packet.rs +++ b/ethcore/sync/src/chain/sync_packet.rs @@ -32,7 +32,7 @@ use crate::api::{ETH_PROTOCOL, WARP_SYNC_PROTOCOL_ID}; /// check whether a given packet id is known, and to prevent /// packet id clashes when defining new ids. -#[derive(SyncPackets, Clone, Copy, Debug, PartialEq)] +#[derive(SyncPackets, Clone, Copy)] pub enum SyncPacket { #[protocol(ETH_PROTOCOL)] StatusPacket = 0x00, #[protocol(ETH_PROTOCOL)] NewBlockHashesPacket = 0x01, @@ -56,35 +56,3 @@ pub enum SyncPacket { #[protocol(WARP_SYNC_PROTOCOL_ID)] PrivateTransactionPacket = 0x16, #[protocol(WARP_SYNC_PROTOCOL_ID)] SignedPrivateTransactionPacket = 0x17, } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn packet_ids_from_u8_when_from_primitive_zero_then_equals_status_packet() { - assert_eq!(SyncPacket::from_u8(0x00), Some(StatusPacket)); - } - - #[test] - fn packet_ids_from_u8_when_from_primitive_eleven_then_equals_get_snapshot_manifest_packet() { - assert_eq!(SyncPacket::from_u8(0x11), Some(GetSnapshotManifestPacket)); - } - - #[test] - fn packet_ids_from_u8_when_invalid_packet_id_then_none() { - assert!(SyncPacket::from_u8(0x99).is_none()); - } - - #[test] - fn when_status_packet_then_id_and_protocol_match() { - assert_eq!(StatusPacket.id(), StatusPacket as PacketId); - assert_eq!(StatusPacket.protocol(), ETH_PROTOCOL); - } - - #[test] - fn when_consensus_data_packet_then_id_and_protocol_match() { - assert_eq!(ConsensusDataPacket.id(), ConsensusDataPacket as PacketId); - assert_eq!(ConsensusDataPacket.protocol(), WARP_SYNC_PROTOCOL_ID); - } -} diff --git a/util/syncpacket/Cargo.toml b/util/syncpacket/Cargo.toml index d9c70a005c1..635aa667b05 100644 --- a/util/syncpacket/Cargo.toml +++ b/util/syncpacket/Cargo.toml @@ -12,3 +12,6 @@ proc-macro = true syn = "0.15" quote = "0.6" proc-macro2 = "0.4" + +[dev-dependencies] +ethcore-network = {path = "../network"} diff --git a/util/syncpacket/src/lib.rs b/util/syncpacket/src/lib.rs index 3f49b6aec0d..c6e98d3a4aa 100644 --- a/util/syncpacket/src/lib.rs +++ b/util/syncpacket/src/lib.rs @@ -83,7 +83,7 @@ fn get_variant_values(variants: &Punctuated) -> Result Result { let values = get_variant_values(&body.variants)?; Ok(quote!{ - use network::{PacketId, ProtocolId}; + use ethcore_network::{PacketId, ProtocolId}; - impl #enum_name { - pub fn from_u8(id: u8) -> Option { - match id { - #(#values => Some(#idents_from_u8)),*, - _ => None + impl #enum_name { + pub fn from_u8(id: u8) -> Option<#enum_name> { + match id { + #(#values => Some(#idents_from_u8)),*, + _ => None - } } } + } - use self::SyncPacket::*; + use self::#enum_name::*; - /// Provide both subprotocol and packet id information within the - /// same object. - pub trait PacketInfo { - fn id(&self) -> PacketId; - fn protocol(&self) -> ProtocolId; - } + /// Provide both subprotocol and packet id information within the + /// same object. + pub trait PacketInfo { + fn id(&self) -> PacketId; + fn protocol(&self) -> ProtocolId; + } - impl PacketInfo for #enum_name { - fn protocol(&self) -> ProtocolId { - match self { - #(#idents_enum => #protocols),* - } + impl PacketInfo for #enum_name { + fn protocol(&self) -> ProtocolId { + match self { + #(#idents_enum => #protocols),* } + } - fn id(&self) -> PacketId { - (*self) as PacketId - } + fn id(&self) -> PacketId { + (*self) as PacketId } } - ) + }) } diff --git a/util/syncpacket/tests/syncpacket.rs b/util/syncpacket/tests/syncpacket.rs new file mode 100644 index 00000000000..a8d53a5363e --- /dev/null +++ b/util/syncpacket/tests/syncpacket.rs @@ -0,0 +1,51 @@ +// Copyright 2015-2019 Parity Technologies (UK) Ltd. +// This file is part of Parity Ethereum. + +// Parity Ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Ethereum. If not, see . + +#[macro_use] +extern crate syncpacket; + +const MY_PROTOCOL0: ProtocolId = *b"mp0"; +const MY_PROTOCOL1: ProtocolId = *b"mp1"; + +#[derive(SyncPackets, Clone, Copy, Debug, PartialEq)] +enum Packets { + #[protocol(MY_PROTOCOL0)] Packet0 = 0x00, + #[protocol(MY_PROTOCOL1)] Packet1 = 0x01, +} + +#[test] +fn packet_ids_from_u8_when_from_primitive_zero_then_equals_status_packet() { + assert_eq!(Packets::from_u8(0x00), Some(Packets::Packet0)); +} + +#[test] +fn packet_ids_from_u8_when_from_primitive_eleven_then_equals_get_snapshot_manifest_packet() { + assert_eq!(Packets::from_u8(0x01), Some(Packets::Packet1)); +} + +#[test] +fn packet_ids_from_u8_when_invalid_packet_id_then_none() { + assert!(Packets::from_u8(0x99).is_none()); +} + +#[test] +fn when_status_packet_then_id_and_protocol_match() { + assert_eq!(Packets::Packet0.id(), Packets::Packet0 as PacketId); + assert_eq!(Packets::Packet0.protocol(), MY_PROTOCOL0); + + assert_eq!(Packets::Packet1.id(), Packets::Packet1 as PacketId); + assert_eq!(Packets::Packet1.protocol(), MY_PROTOCOL1); +}