diff --git a/Cargo.lock b/Cargo.lock index 87e6a6b79..9a7c22298 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,6 +301,7 @@ dependencies = [ "ethcore-util 1.8.0", "ethjson 0.1.0", "rlp 0.2.0", + "rlp_derive 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -526,6 +527,7 @@ dependencies = [ "price-info 1.7.0", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0", + "rlp_derive 0.1.0", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -652,6 +654,7 @@ dependencies = [ "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0", + "rlp_derive 0.1.0", "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2305,7 +2308,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.3.10" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2396,6 +2399,15 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rlp_derive" +version = "0.1.0" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.2.0", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rocksdb" version = "0.4.5" @@ -2588,7 +2600,7 @@ name = "serde_derive" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2730,7 +2742,7 @@ name = "syn" version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3384,7 +3396,7 @@ dependencies = [ "checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum quine-mc_cluskey 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6683b0e23d80813b1a535841f0048c1537d3f86d63c999e8373b39a9b0eb74a" -"checksum quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6732e32663c9c271bfc7c1823486b471f18c47a2dbf87c066897b7b51afc83be" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" "checksum rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c83adcb08e5b922e804fe1918142b422602ef11f2fd670b0b52218cb5984a20" "checksum rayon-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "767d91bacddf07d442fe39257bf04fd95897d1c47c545d009f6beb03efd038f8" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 0b4abc1bb..c49e31898 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -47,6 +47,7 @@ num_cpus = "1.2" price-info = { path = "../price-info" } rand = "0.3" rlp = { path = "../util/rlp" } +rlp_derive = { path = "../util/rlp_derive" } rust-crypto = "0.2.34" rustc-hex = "1.0" semver = "0.6" diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index b652050d2..9fda78f47 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -21,6 +21,7 @@ ethcore-devtools = { path = "../../devtools" } evm = { path = "../evm" } vm = { path = "../vm" } rlp = { path = "../../util/rlp" } +rlp_derive = { path = "../../util/rlp_derive" } time = "0.1" smallvec = "0.4" futures = "0.1" diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index b172134cf..c2ab483d2 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -76,6 +76,8 @@ extern crate futures; extern crate itertools; extern crate rand; extern crate rlp; +#[macro_use] +extern crate rlp_derive; extern crate serde; extern crate smallvec; extern crate stats; diff --git a/ethcore/light/src/types/request/mod.rs b/ethcore/light/src/types/request/mod.rs index ff4a32535..51f916b15 100644 --- a/ethcore/light/src/types/request/mod.rs +++ b/ethcore/light/src/types/request/mod.rs @@ -650,7 +650,7 @@ pub mod header { use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; /// Potentially incomplete headers request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Start block. pub start: Field, @@ -662,27 +662,6 @@ pub mod header { pub reverse: bool, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - start: rlp.val_at(0)?, - skip: rlp.val_at(1)?, - max: rlp.val_at(2)?, - reverse: rlp.val_at(3)? - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4) - .append(&self.start) - .append(&self.skip) - .append(&self.max) - .append(&self.reverse); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -784,26 +763,12 @@ pub mod header_proof { use util::{Bytes, U256, H256}; /// Potentially incomplete header proof request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block number. pub num: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - num: rlp.val_at(0)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(1).append(&self.num); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -889,30 +854,15 @@ pub mod header_proof { /// Request and response for transaction index. pub mod transaction_index { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::H256; /// Potentially incomplete transaction index request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Transaction hash to get index for. pub hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - hash: rlp.val_at(0)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(1).append(&self.hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -959,7 +909,7 @@ pub mod transaction_index { } /// The output of a request for transaction index. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Response { /// Block number. pub num: u64, @@ -976,55 +926,21 @@ pub mod transaction_index { f(1, Output::Hash(self.hash)); } } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Response { - num: rlp.val_at(0)?, - hash: rlp.val_at(1)?, - index: rlp.val_at(2)?, - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3) - .append(&self.num) - .append(&self.hash) - .append(&self.index); - } - } } /// Request and response for block receipts pub mod block_receipts { use super::{Field, NoSuchOutput, OutputKind, Output}; use ethcore::receipt::Receipt; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::H256; /// Potentially incomplete block receipts request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block hash to get receipts for. pub hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - hash: rlp.val_at(0)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(1).append(&self.hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1068,7 +984,7 @@ pub mod block_receipts { } /// The output of a request for block receipts. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct Response { /// The block receipts. pub receipts: Vec @@ -1078,20 +994,6 @@ pub mod block_receipts { /// Fill reusable outputs by providing them to the function. fn fill_outputs(&self, _: F) where F: FnMut(usize, Output) {} } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Response { - receipts: rlp.as_list()?, - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.receipts); - } - } } /// Request and response for a block body @@ -1102,26 +1004,12 @@ pub mod block_body { use util::H256; /// Potentially incomplete block body request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block hash to get receipts for. pub hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - hash: rlp.val_at(0)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(1).append(&self.hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1201,11 +1089,10 @@ pub mod block_body { /// A request for an account proof. pub mod account { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::{Bytes, U256, H256}; /// Potentially incomplete request for an account proof. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block hash to request state proof for. pub block_hash: Field, @@ -1213,23 +1100,6 @@ pub mod account { pub address_hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - block_hash: rlp.val_at(0)?, - address_hash: rlp.val_at(1)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2) - .append(&self.block_hash) - .append(&self.address_hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1292,7 +1162,7 @@ pub mod account { } /// The output of a request for an account state proof. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Response { /// Inclusion/exclusion proof pub proof: Vec, @@ -1313,39 +1183,15 @@ pub mod account { f(1, Output::Hash(self.storage_root)); } } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Response { - proof: rlp.list_at(0)?, - nonce: rlp.val_at(1)?, - balance: rlp.val_at(2)?, - code_hash: rlp.val_at(3)?, - storage_root: rlp.val_at(4)? - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(5) - .append_list::,_>(&self.proof[..]) - .append(&self.nonce) - .append(&self.balance) - .append(&self.code_hash) - .append(&self.storage_root); - } - } } /// A request for a storage proof. pub mod storage { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::{Bytes, H256}; /// Potentially incomplete request for an storage proof. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block hash to request state proof for. pub block_hash: Field, @@ -1355,25 +1201,6 @@ pub mod storage { pub key_hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - block_hash: rlp.val_at(0)?, - address_hash: rlp.val_at(1)?, - key_hash: rlp.val_at(2)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3) - .append(&self.block_hash) - .append(&self.address_hash) - .append(&self.key_hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1450,7 +1277,7 @@ pub mod storage { } /// The output of a request for an account state proof. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Response { /// Inclusion/exclusion proof pub proof: Vec, @@ -1464,33 +1291,15 @@ pub mod storage { f(0, Output::Hash(self.value)); } } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Response { - proof: rlp.list_at(0)?, - value: rlp.val_at(1)?, - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2) - .append_list::,_>(&self.proof[..]) - .append(&self.value); - } - } } /// A request for contract code. pub mod contract_code { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::{Bytes, H256}; /// Potentially incomplete contract code request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// The block hash to request the state for. pub block_hash: Field, @@ -1498,23 +1307,6 @@ pub mod contract_code { pub code_hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - block_hash: rlp.val_at(0)?, - code_hash: rlp.val_at(1)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2) - .append(&self.block_hash) - .append(&self.code_hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1573,7 +1365,7 @@ pub mod contract_code { } /// The output of a request for - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct Response { /// The requested code. pub code: Bytes, @@ -1583,21 +1375,6 @@ pub mod contract_code { /// Fill reusable outputs by providing them to the function. fn fill_outputs(&self, _: F) where F: FnMut(usize, Output) {} } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - - Ok(Response { - code: rlp.as_val()?, - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.append(&self.code); - } - } } /// A request for proof of execution. @@ -1608,7 +1385,7 @@ pub mod execution { use util::{Bytes, Address, U256, H256, DBValue}; /// Potentially incomplete execution proof request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// The block hash to request the state for. pub block_hash: Field, @@ -1626,38 +1403,6 @@ pub mod execution { pub data: Bytes, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - block_hash: rlp.val_at(0)?, - from: rlp.val_at(1)?, - action: rlp.val_at(2)?, - gas: rlp.val_at(3)?, - gas_price: rlp.val_at(4)?, - value: rlp.val_at(5)?, - data: rlp.val_at(6)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(7) - .append(&self.block_hash) - .append(&self.from); - - match self.action { - Action::Create => s.append_empty_data(), - Action::Call(ref addr) => s.append(addr), - }; - - s.append(&self.gas) - .append(&self.gas_price) - .append(&self.value) - .append(&self.data); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index ed3a5009b..0e2396f8c 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -25,11 +25,9 @@ use engines::epoch::{Transition as EpochTransition}; use header::BlockNumber; use receipt::Receipt; -use rlp::*; -use util::*; +use util::{HeapSizeOf, H256, H264, U256}; use util::kvdb::PREFIX_LEN as DB_PREFIX_LEN; - /// Represents index of extra data in database #[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] pub enum ExtrasIndex { @@ -184,7 +182,7 @@ impl Key for u64 { } /// Familial details concerning a block -#[derive(Debug, Clone)] +#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] pub struct BlockDetails { /// Block number pub number: BlockNumber, @@ -202,30 +200,8 @@ impl HeapSizeOf for BlockDetails { } } -impl Decodable for BlockDetails { - fn decode(rlp: &UntrustedRlp) -> Result { - let details = BlockDetails { - number: rlp.val_at(0)?, - total_difficulty: rlp.val_at(1)?, - parent: rlp.val_at(2)?, - children: rlp.list_at(3)?, - }; - Ok(details) - } -} - -impl Encodable for BlockDetails { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.number); - s.append(&self.total_difficulty); - s.append(&self.parent); - s.append_list(&self.children); - } -} - /// Represents address of certain transaction within block -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] pub struct TransactionAddress { /// Block hash pub block_hash: H256, @@ -237,27 +213,8 @@ impl HeapSizeOf for TransactionAddress { fn heap_size_of_children(&self) -> usize { 0 } } -impl Decodable for TransactionAddress { - fn decode(rlp: &UntrustedRlp) -> Result { - let tx_address = TransactionAddress { - block_hash: rlp.val_at(0)?, - index: rlp.val_at(1)?, - }; - - Ok(tx_address) - } -} - -impl Encodable for TransactionAddress { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.block_hash); - s.append(&self.index); - } -} - /// Contains all block receipts. -#[derive(Clone)] +#[derive(Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct BlockReceipts { pub receipts: Vec, } @@ -270,20 +227,6 @@ impl BlockReceipts { } } -impl Decodable for BlockReceipts { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(BlockReceipts { - receipts: rlp.as_list()?, - }) - } -} - -impl Encodable for BlockReceipts { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.receipts); - } -} - impl HeapSizeOf for BlockReceipts { fn heap_size_of_children(&self) -> usize { self.receipts.heap_size_of_children() @@ -291,27 +234,12 @@ impl HeapSizeOf for BlockReceipts { } /// Candidate transitions to an epoch with specific number. -#[derive(Clone)] +#[derive(Clone, RlpEncodable, RlpDecodable)] pub struct EpochTransitions { pub number: u64, pub candidates: Vec, } -impl Encodable for EpochTransitions { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2).append(&self.number).append_list(&self.candidates); - } -} - -impl Decodable for EpochTransitions { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(EpochTransitions { - number: rlp.val_at(0)?, - candidates: rlp.list_at(1)?, - }) - } -} - #[cfg(test)] mod tests { use rlp::*; diff --git a/ethcore/src/blooms/bloom.rs b/ethcore/src/blooms/bloom.rs index cac9ff448..c79091cb4 100644 --- a/ethcore/src/blooms/bloom.rs +++ b/ethcore/src/blooms/bloom.rs @@ -15,12 +15,11 @@ // along with Parity. If not, see . use bloomchain as bc; -use rlp::*; use util::HeapSizeOf; use basic_types::LogBloom; /// Helper structure representing bloom of the trace. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct Bloom(LogBloom); impl From for Bloom { @@ -43,18 +42,6 @@ impl Into for Bloom { } } -impl Decodable for Bloom { - fn decode(rlp: &UntrustedRlp) -> Result { - LogBloom::decode(rlp).map(Bloom) - } -} - -impl Encodable for Bloom { - fn rlp_append(&self, s: &mut RlpStream) { - Encodable::rlp_append(&self.0, s) - } -} - impl HeapSizeOf for Bloom { fn heap_size_of_children(&self) -> usize { 0 diff --git a/ethcore/src/engines/epoch.rs b/ethcore/src/engines/epoch.rs index f738113cf..586059e83 100644 --- a/ethcore/src/engines/epoch.rs +++ b/ethcore/src/engines/epoch.rs @@ -16,14 +16,12 @@ //! Epoch verifiers and transitions. +use util::H256; use error::Error; use header::Header; -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; -use util::H256; - /// A full epoch transition. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] pub struct Transition { /// Block hash at which the transition occurred. pub block_hash: H256, @@ -33,46 +31,14 @@ pub struct Transition { pub proof: Vec, } -impl Encodable for Transition { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3) - .append(&self.block_hash) - .append(&self.block_number) - .append(&self.proof); - } -} - -impl Decodable for Transition { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Transition { - block_hash: rlp.val_at(0)?, - block_number: rlp.val_at(1)?, - proof: rlp.val_at(2)?, - }) - } -} - /// An epoch transition pending a finality proof. /// Not all transitions need one. +#[derive(RlpEncodableWrapper, RlpDecodableWrapper)] pub struct PendingTransition { /// "transition/epoch" proof from the engine. pub proof: Vec, } -impl Encodable for PendingTransition { - fn rlp_append(&self, s: &mut RlpStream) { - s.append(&self.proof); - } -} - -impl Decodable for PendingTransition { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(PendingTransition { - proof: rlp.as_val()?, - }) - } -} - /// Verifier for all blocks within an epoch with self-contained state. /// /// See docs on `Engine` relating to proving functions for more details. diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 6c862ecda..15d44626b 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -101,6 +101,9 @@ extern crate num; extern crate price_info; extern crate rand; extern crate rlp; + +#[macro_use] +extern crate rlp_derive; extern crate rustc_hex; extern crate semver; extern crate stats; diff --git a/ethcore/src/snapshot/io.rs b/ethcore/src/snapshot/io.rs index 8cb778117..f28adcf7f 100644 --- a/ethcore/src/snapshot/io.rs +++ b/ethcore/src/snapshot/io.rs @@ -27,7 +27,7 @@ use std::path::{Path, PathBuf}; use util::Bytes; use util::hash::H256; -use rlp::{self, Encodable, RlpStream, UntrustedRlp}; +use rlp::{RlpStream, UntrustedRlp}; use super::ManifestData; @@ -49,24 +49,9 @@ pub trait SnapshotWriter { } // (hash, len, offset) +#[derive(RlpEncodable, RlpDecodable)] struct ChunkInfo(H256, u64, u64); -impl Encodable for ChunkInfo { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.0).append(&self.1).append(&self.2); - } -} - -impl rlp::Decodable for ChunkInfo { - fn decode(rlp: &UntrustedRlp) -> Result { - let hash = rlp.val_at(0)?; - let len = rlp.val_at(1)?; - let off = rlp.val_at(2)?; - Ok(ChunkInfo(hash, len, off)) - } -} - /// A packed snapshot writer. This writes snapshots to a single concatenated file. /// /// The file format is very simple and consists of three parts: diff --git a/ethcore/src/trace/bloom.rs b/ethcore/src/trace/bloom.rs index 561a83719..ed34d6505 100644 --- a/ethcore/src/trace/bloom.rs +++ b/ethcore/src/trace/bloom.rs @@ -1,10 +1,9 @@ use bloomchain::Bloom; use bloomchain::group::{BloomGroup, GroupPosition}; -use rlp::*; use basic_types::LogBloom; /// Helper structure representing bloom of the trace. -#[derive(Clone)] +#[derive(Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct BlockTracesBloom(LogBloom); impl From for BlockTracesBloom { @@ -28,7 +27,7 @@ impl Into for BlockTracesBloom { } /// Represents group of X consecutive blooms. -#[derive(Clone)] +#[derive(Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct BlockTracesBloomGroup { blooms: Vec, } @@ -59,34 +58,6 @@ impl Into for BlockTracesBloomGroup { } } -impl Decodable for BlockTracesBloom { - fn decode(rlp: &UntrustedRlp) -> Result { - LogBloom::decode(rlp).map(BlockTracesBloom) - } -} - -impl Encodable for BlockTracesBloom { - fn rlp_append(&self, s: &mut RlpStream) { - Encodable::rlp_append(&self.0, s) - } -} - -impl Decodable for BlockTracesBloomGroup { - fn decode(rlp: &UntrustedRlp) -> Result { - let blooms = rlp.as_list()?; - let group = BlockTracesBloomGroup { - blooms: blooms - }; - Ok(group) - } -} - -impl Encodable for BlockTracesBloomGroup { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.blooms); - } -} - /// Represents `BloomGroup` position in database. #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub struct TraceGroupPosition { diff --git a/ethcore/src/trace/types/flat.rs b/ethcore/src/trace/types/flat.rs index da304694d..8b65f1f4c 100644 --- a/ethcore/src/trace/types/flat.rs +++ b/ethcore/src/trace/types/flat.rs @@ -77,7 +77,7 @@ impl Decodable for FlatTrace { } /// Represents all traces produced by a single transaction. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct FlatTransactionTraces(Vec); impl From> for FlatTransactionTraces { @@ -99,18 +99,6 @@ impl FlatTransactionTraces { } } -impl Encodable for FlatTransactionTraces { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.0); - } -} - -impl Decodable for FlatTransactionTraces { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(FlatTransactionTraces(rlp.as_list()?)) - } -} - impl Into> for FlatTransactionTraces { fn into(self) -> Vec { self.0 @@ -118,7 +106,7 @@ impl Into> for FlatTransactionTraces { } /// Represents all traces produced by transactions in a single block. -#[derive(Debug, PartialEq, Clone, Default)] +#[derive(Debug, PartialEq, Clone, Default, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct FlatBlockTraces(Vec); impl HeapSizeOf for FlatBlockTraces { @@ -140,18 +128,6 @@ impl FlatBlockTraces { } } -impl Encodable for FlatBlockTraces { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.0); - } -} - -impl Decodable for FlatBlockTraces { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(FlatBlockTraces(rlp.as_list()?)) - } -} - impl Into> for FlatBlockTraces { fn into(self) -> Vec { self.0 diff --git a/ethcore/src/trace/types/trace.rs b/ethcore/src/trace/types/trace.rs index 3863a935e..5fa0260c6 100644 --- a/ethcore/src/trace/types/trace.rs +++ b/ethcore/src/trace/types/trace.rs @@ -27,7 +27,7 @@ use evm::CallType; use super::error::Error; /// `Call` result. -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct CallResult { /// Gas used by call. @@ -36,27 +36,8 @@ pub struct CallResult { pub output: Bytes, } -impl Encodable for CallResult { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.gas_used); - s.append(&self.output); - } -} - -impl Decodable for CallResult { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = CallResult { - gas_used: rlp.val_at(0)?, - output: rlp.val_at(1)?, - }; - - Ok(res) - } -} - /// `Create` result. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct CreateResult { /// Gas used by create. @@ -67,27 +48,6 @@ pub struct CreateResult { pub address: Address, } -impl Encodable for CreateResult { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.gas_used); - s.append(&self.code); - s.append(&self.address); - } -} - -impl Decodable for CreateResult { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = CreateResult { - gas_used: rlp.val_at(0)?, - code: rlp.val_at(1)?, - address: rlp.val_at(2)?, - }; - - Ok(res) - } -} - impl CreateResult { /// Returns bloom. pub fn bloom(&self) -> LogBloom { @@ -96,7 +56,7 @@ impl CreateResult { } /// Description of a _call_ action, either a `CALL` operation or a message transction. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct Call { /// The sending account. @@ -126,33 +86,6 @@ impl From for Call { } } -impl Encodable for Call { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(6); - s.append(&self.from); - s.append(&self.to); - s.append(&self.value); - s.append(&self.gas); - s.append(&self.input); - s.append(&self.call_type); - } -} - -impl Decodable for Call { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = Call { - from: rlp.val_at(0)?, - to: rlp.val_at(1)?, - value: rlp.val_at(2)?, - gas: rlp.val_at(3)?, - input: rlp.val_at(4)?, - call_type: rlp.val_at(5)?, - }; - - Ok(res) - } -} - impl Call { /// Returns call action bloom. /// The bloom contains from and to addresses. @@ -163,7 +96,7 @@ impl Call { } /// Description of a _create_ action, either a `CREATE` operation or a create transction. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct Create { /// The address of the creator. @@ -187,29 +120,6 @@ impl From for Create { } } -impl Encodable for Create { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.from); - s.append(&self.value); - s.append(&self.gas); - s.append(&self.init); - } -} - -impl Decodable for Create { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = Create { - from: rlp.val_at(0)?, - value: rlp.val_at(1)?, - gas: rlp.val_at(2)?, - init: rlp.val_at(3)?, - }; - - Ok(res) - } -} - impl Create { /// Returns bloom create action bloom. /// The bloom contains only from address. @@ -219,7 +129,7 @@ impl Create { } /// Suicide action. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct Suicide { /// Suicided address. @@ -238,28 +148,6 @@ impl Suicide { } } -impl Encodable for Suicide { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.address); - s.append(&self.refund_address); - s.append(&self.balance); - } -} - -impl Decodable for Suicide { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = Suicide { - address: rlp.val_at(0)?, - refund_address: rlp.val_at(1)?, - balance: rlp.val_at(2)?, - }; - - Ok(res) - } -} - - /// Description of an action that we trace; will be either a call or a create. #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "ipc", binary)] @@ -394,7 +282,7 @@ impl Res { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A diff of some chunk of memory. pub struct MemoryDiff { @@ -404,24 +292,7 @@ pub struct MemoryDiff { pub data: Bytes, } -impl Encodable for MemoryDiff { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.offset); - s.append(&self.data); - } -} - -impl Decodable for MemoryDiff { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(MemoryDiff { - offset: rlp.val_at(0)?, - data: rlp.val_at(1)?, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A diff of some storage value. pub struct StorageDiff { @@ -431,24 +302,7 @@ pub struct StorageDiff { pub value: U256, } -impl Encodable for StorageDiff { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.location); - s.append(&self.value); - } -} - -impl Decodable for StorageDiff { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(StorageDiff { - location: rlp.val_at(0)?, - value: rlp.val_at(1)?, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A record of an executed VM operation. pub struct VMExecutedOperation { @@ -462,28 +316,7 @@ pub struct VMExecutedOperation { pub store_diff: Option, } -impl Encodable for VMExecutedOperation { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.gas_used); - s.append_list(&self.stack_push); - s.append(&self.mem_diff); - s.append(&self.store_diff); - } -} - -impl Decodable for VMExecutedOperation { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(VMExecutedOperation { - gas_used: rlp.val_at(0)?, - stack_push: rlp.list_at(1)?, - mem_diff: rlp.val_at(2)?, - store_diff: rlp.val_at(3)?, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A record of the execution of a single VM operation. pub struct VMOperation { @@ -497,30 +330,7 @@ pub struct VMOperation { pub executed: Option, } -impl Encodable for VMOperation { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.pc); - s.append(&self.instruction); - s.append(&self.gas_cost); - s.append(&self.executed); - } -} - -impl Decodable for VMOperation { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = VMOperation { - pc: rlp.val_at(0)?, - instruction: rlp.val_at(1)?, - gas_cost: rlp.val_at(2)?, - executed: rlp.val_at(3)?, - }; - - Ok(res) - } -} - -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A record of a full VM trace for a CALL/CREATE. pub struct VMTrace { @@ -534,26 +344,3 @@ pub struct VMTrace { /// Thre is a 1:1 correspondance between these and a CALL/CREATE/CALLCODE/DELEGATECALL instruction. pub subs: Vec, } - -impl Encodable for VMTrace { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.parent_step); - s.append(&self.code); - s.append_list(&self.operations); - s.append_list(&self.subs); - } -} - -impl Decodable for VMTrace { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = VMTrace { - parent_step: rlp.val_at(0)?, - code: rlp.val_at(1)?, - operations: rlp.list_at(2)?, - subs: rlp.list_at(3)?, - }; - - Ok(res) - } -} diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 6f5470028..2752cc6dd 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -56,6 +56,15 @@ impl Decodable for Action { } } +impl Encodable for Action { + fn rlp_append(&self, s: &mut RlpStream) { + match *self { + Action::Create => s.append_internal(&""), + Action::Call(ref addr) => s.append_internal(addr), + }; + } +} + /// Transaction activation condition. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Condition { @@ -90,10 +99,7 @@ impl Transaction { s.append(&self.nonce); s.append(&self.gas_price); s.append(&self.gas); - match self.action { - Action::Create => s.append_empty_data(), - Action::Call(ref to) => s.append(to) - }; + s.append(&self.action); s.append(&self.value); s.append(&self.data); if let Some(n) = network_id { @@ -308,10 +314,7 @@ impl UnverifiedTransaction { s.append(&self.nonce); s.append(&self.gas_price); s.append(&self.gas); - match self.action { - Action::Create => s.append_empty_data(), - Action::Call(ref to) => s.append(to) - }; + s.append(&self.action); s.append(&self.value); s.append(&self.data); s.append(&self.v); diff --git a/ethcore/types/Cargo.toml b/ethcore/types/Cargo.toml index 77f392bf6..82963f960 100644 --- a/ethcore/types/Cargo.toml +++ b/ethcore/types/Cargo.toml @@ -6,6 +6,7 @@ authors = ["Parity Technologies "] [dependencies] rlp = { path = "../../util/rlp" } +rlp_derive = { path = "../../util/rlp_derive" } ethcore-util = { path = "../../util" } ethjson = { path = "../../json" } bloomable = { path = "../../util/bloomable" } diff --git a/ethcore/types/src/basic_account.rs b/ethcore/types/src/basic_account.rs index c071040cf..f30872f6b 100644 --- a/ethcore/types/src/basic_account.rs +++ b/ethcore/types/src/basic_account.rs @@ -16,11 +16,10 @@ //! Basic account type -- the decoded RLP from the state trie. -use rlp::*; use util::{U256, H256}; /// Basic account type. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct BasicAccount { /// Nonce of the account. pub nonce: U256, @@ -31,24 +30,3 @@ pub struct BasicAccount { /// Code hash of the account. pub code_hash: H256, } - -impl Encodable for BasicAccount { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4) - .append(&self.nonce) - .append(&self.balance) - .append(&self.storage_root) - .append(&self.code_hash); - } -} - -impl Decodable for BasicAccount { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(BasicAccount { - nonce: rlp.val_at(0)?, - balance: rlp.val_at(1)?, - storage_root: rlp.val_at(2)?, - code_hash: rlp.val_at(3)?, - }) - } -} diff --git a/ethcore/types/src/lib.rs b/ethcore/types/src/lib.rs index 7650cf651..10a4ac71e 100644 --- a/ethcore/types/src/lib.rs +++ b/ethcore/types/src/lib.rs @@ -19,6 +19,8 @@ extern crate ethcore_util as util; extern crate ethjson; extern crate rlp; +#[macro_use] +extern crate rlp_derive; extern crate bloomable; #[cfg(test)] diff --git a/ethcore/types/src/log_entry.rs b/ethcore/types/src/log_entry.rs index f917a4dab..152b48a0e 100644 --- a/ethcore/types/src/log_entry.rs +++ b/ethcore/types/src/log_entry.rs @@ -19,7 +19,6 @@ use std::ops::Deref; use util::{H256, Address, Bytes, HeapSizeOf, Hashable}; use bloomable::Bloomable; -use rlp::*; use {BlockNumber}; use ethjson; @@ -27,7 +26,7 @@ use ethjson; pub type LogBloom = ::util::H2048; /// A record of execution for a `LOG` operation. -#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct LogEntry { /// The address of the contract executing at the point of the `LOG` operation. pub address: Address, @@ -37,26 +36,6 @@ pub struct LogEntry { pub data: Bytes, } -impl Encodable for LogEntry { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.address); - s.append_list(&self.topics); - s.append(&self.data); - } -} - -impl Decodable for LogEntry { - fn decode(rlp: &UntrustedRlp) -> Result { - let entry = LogEntry { - address: rlp.val_at(0)?, - topics: rlp.list_at(1)?, - data: rlp.val_at(2)?, - }; - Ok(entry) - } -} - impl HeapSizeOf for LogEntry { fn heap_size_of_children(&self) -> usize { self.topics.heap_size_of_children() + self.data.heap_size_of_children() diff --git a/util/rlp_derive/Cargo.toml b/util/rlp_derive/Cargo.toml new file mode 100644 index 000000000..81e50cd44 --- /dev/null +++ b/util/rlp_derive/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rlp_derive" +version = "0.1.0" +authors = ["debris "] + +[lib] +name = "rlp_derive" +proc-macro = true + +[dependencies] +syn = "0.11.11" +quote = "0.3.15" + +[dev-dependencies] +rlp = { path = "../rlp" } diff --git a/util/rlp_derive/src/de.rs b/util/rlp_derive/src/de.rs new file mode 100644 index 000000000..a3e32739a --- /dev/null +++ b/util/rlp_derive/src/de.rs @@ -0,0 +1,139 @@ +use {syn, quote}; + +struct ParseQuotes { + single: quote::Tokens, + list: quote::Tokens, + takes_index: bool, +} + +fn decodable_parse_quotes() -> ParseQuotes { + ParseQuotes { + single: quote! { rlp.val_at }, + list: quote! { rlp.list_at }, + takes_index: true, + } +} + +fn decodable_wrapper_parse_quotes() -> ParseQuotes { + ParseQuotes { + single: quote! { rlp.as_val }, + list: quote! { rlp.as_list }, + takes_index: false, + } +} + +pub fn impl_decodable(ast: &syn::DeriveInput) -> quote::Tokens { + let body = match ast.body { + syn::Body::Struct(ref s) => s, + _ => panic!("#[derive(RlpDecodable)] is only defined for structs."), + }; + + let stmts: Vec<_> = match *body { + syn::VariantData::Struct(ref fields) | syn::VariantData::Tuple(ref fields) => + fields.iter().enumerate().map(decodable_field_map).collect(), + syn::VariantData::Unit => panic!("#[derive(RlpDecodable)] is not defined for Unit structs."), + }; + + let name = &ast.ident; + + let dummy_const = syn::Ident::new(format!("_IMPL_RLP_DECODABLE_FOR_{}", name)); + let impl_block = quote! { + impl rlp::Decodable for #name { + fn decode(rlp: &rlp::UntrustedRlp) -> Result { + let result = #name { + #(#stmts)* + }; + + Ok(result) + } + } + }; + + quote! { + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const #dummy_const: () = { + extern crate rlp; + #impl_block + }; + } +} + +pub fn impl_decodable_wrapper(ast: &syn::DeriveInput) -> quote::Tokens { + let body = match ast.body { + syn::Body::Struct(ref s) => s, + _ => panic!("#[derive(RlpDecodableWrapper)] is only defined for structs."), + }; + + let stmt = match *body { + syn::VariantData::Struct(ref fields) | syn::VariantData::Tuple(ref fields) => { + if fields.len() == 1 { + let field = fields.first().expect("fields.len() == 1; qed"); + decodable_field(0, field, decodable_wrapper_parse_quotes()) + } else { + panic!("#[derive(RlpDecodableWrapper)] is only defined for structs with one field.") + } + }, + syn::VariantData::Unit => panic!("#[derive(RlpDecodableWrapper)] is not defined for Unit structs."), + }; + + let name = &ast.ident; + + let dummy_const = syn::Ident::new(format!("_IMPL_RLP_DECODABLE_FOR_{}", name)); + let impl_block = quote! { + impl rlp::Decodable for #name { + fn decode(rlp: &rlp::UntrustedRlp) -> Result { + let result = #name { + #stmt + }; + + Ok(result) + } + } + }; + + quote! { + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const #dummy_const: () = { + extern crate rlp; + #impl_block + }; + } +} + +fn decodable_field_map(tuple: (usize, &syn::Field)) -> quote::Tokens { + decodable_field(tuple.0, tuple.1, decodable_parse_quotes()) +} + +fn decodable_field(index: usize, field: &syn::Field, quotes: ParseQuotes) -> quote::Tokens { + let ident = match field.ident { + Some(ref ident) => ident.to_string(), + None => index.to_string(), + }; + + let id = syn::Ident::new(ident); + let index = syn::Ident::new(index.to_string()); + + let single = quotes.single; + let list = quotes.list; + + match field.ty { + syn::Ty::Path(_, ref path) => { + let ident = &path.segments.first().expect("there must be at least 1 segment").ident; + if &ident.to_string() == "Vec" { + if quotes.takes_index { + quote! { #id: #list(#index)?, } + } else { + quote! { #id: #list()?, } + } + } else { + if quotes.takes_index { + quote! { #id: #single(#index)?, } + } else { + quote! { #id: #single()?, } + } + } + }, + _ => panic!("rlp_derive not supported"), + } +} + diff --git a/util/rlp_derive/src/en.rs b/util/rlp_derive/src/en.rs new file mode 100644 index 000000000..77f361200 --- /dev/null +++ b/util/rlp_derive/src/en.rs @@ -0,0 +1,110 @@ +use {syn, quote}; + +pub fn impl_encodable(ast: &syn::DeriveInput) -> quote::Tokens { + let body = match ast.body { + syn::Body::Struct(ref s) => s, + _ => panic!("#[derive(RlpEncodable)] is only defined for structs."), + }; + + let stmts: Vec<_> = match *body { + syn::VariantData::Struct(ref fields) | syn::VariantData::Tuple(ref fields) => + fields.iter().enumerate().map(encodable_field_map).collect(), + syn::VariantData::Unit => panic!("#[derive(RlpEncodable)] is not defined for Unit structs."), + }; + + let name = &ast.ident; + + let stmts_len = syn::Ident::new(stmts.len().to_string()); + let dummy_const = syn::Ident::new(format!("_IMPL_RLP_ENCODABLE_FOR_{}", name)); + let impl_block = quote! { + impl rlp::Encodable for #name { + fn rlp_append(&self, stream: &mut rlp::RlpStream) { + stream.begin_list(#stmts_len); + #(#stmts)* + } + } + }; + + quote! { + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const #dummy_const: () = { + extern crate rlp; + #impl_block + }; + } +} + +pub fn impl_encodable_wrapper(ast: &syn::DeriveInput) -> quote::Tokens { + let body = match ast.body { + syn::Body::Struct(ref s) => s, + _ => panic!("#[derive(RlpEncodableWrapper)] is only defined for structs."), + }; + + let stmt = match *body { + syn::VariantData::Struct(ref fields) | syn::VariantData::Tuple(ref fields) => { + if fields.len() == 1 { + let field = fields.first().expect("fields.len() == 1; qed"); + encodable_field(0, field) + } else { + panic!("#[derive(RlpEncodableWrapper)] is only defined for structs with one field.") + } + }, + syn::VariantData::Unit => panic!("#[derive(RlpEncodableWrapper)] is not defined for Unit structs."), + }; + + let name = &ast.ident; + + let dummy_const = syn::Ident::new(format!("_IMPL_RLP_ENCODABLE_FOR_{}", name)); + let impl_block = quote! { + impl rlp::Encodable for #name { + fn rlp_append(&self, stream: &mut rlp::RlpStream) { + #stmt + } + } + }; + + quote! { + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const #dummy_const: () = { + extern crate rlp; + #impl_block + }; + } +} + +fn encodable_field_map(tuple: (usize, &syn::Field)) -> quote::Tokens { + encodable_field(tuple.0, tuple.1) +} + +fn encodable_field(index: usize, field: &syn::Field) -> quote::Tokens { + let ident = match field.ident { + Some(ref ident) => ident.to_string(), + None => index.to_string(), + }; + + let id = syn::Ident::new(format!("self.{}", ident)); + + match field.ty { + syn::Ty::Path(_, ref path) => { + let top_segment = path.segments.first().expect("there must be at least 1 segment"); + let ident = &top_segment.ident; + if &ident.to_string() == "Vec" { + let inner_ident = match top_segment.parameters { + syn::PathParameters::AngleBracketed(ref angle) => { + let ty = angle.types.first().expect("Vec has only one angle bracketed type; qed"); + match *ty { + syn::Ty::Path(_, ref path) => &path.segments.first().expect("there must be at least 1 segment").ident, + _ => panic!("rlp_derive not supported"), + } + }, + _ => unreachable!("Vec has only one angle bracketed type; qed"), + }; + quote! { stream.append_list::<#inner_ident, _>(&#id); } + } else { + quote! { stream.append(&#id); } + } + }, + _ => panic!("rlp_derive not supported"), + } +} + diff --git a/util/rlp_derive/src/lib.rs b/util/rlp_derive/src/lib.rs new file mode 100644 index 000000000..9c598d08e --- /dev/null +++ b/util/rlp_derive/src/lib.rs @@ -0,0 +1,43 @@ +extern crate proc_macro; +extern crate syn; +#[macro_use] +extern crate quote; + +mod en; +mod de; + +use proc_macro::TokenStream; +use en::{impl_encodable, impl_encodable_wrapper}; +use de::{impl_decodable, impl_decodable_wrapper}; + +#[proc_macro_derive(RlpEncodable)] +pub fn encodable(input: TokenStream) -> TokenStream { + let s = input.to_string(); + let ast = syn::parse_derive_input(&s).unwrap(); + let gen = impl_encodable(&ast); + gen.parse().unwrap() +} + +#[proc_macro_derive(RlpEncodableWrapper)] +pub fn encodable_wrapper(input: TokenStream) -> TokenStream { + let s = input.to_string(); + let ast = syn::parse_derive_input(&s).unwrap(); + let gen = impl_encodable_wrapper(&ast); + gen.parse().unwrap() +} + +#[proc_macro_derive(RlpDecodable)] +pub fn decodable(input: TokenStream) -> TokenStream { + let s = input.to_string(); + let ast = syn::parse_derive_input(&s).unwrap(); + let gen = impl_decodable(&ast); + gen.parse().unwrap() +} + +#[proc_macro_derive(RlpDecodableWrapper)] +pub fn decodable_wrapper(input: TokenStream) -> TokenStream { + let s = input.to_string(); + let ast = syn::parse_derive_input(&s).unwrap(); + let gen = impl_decodable_wrapper(&ast); + gen.parse().unwrap() +} diff --git a/util/rlp_derive/tests/rlp.rs b/util/rlp_derive/tests/rlp.rs new file mode 100644 index 000000000..c87380524 --- /dev/null +++ b/util/rlp_derive/tests/rlp.rs @@ -0,0 +1,44 @@ +extern crate rlp; +#[macro_use] +extern crate rlp_derive; + +use rlp::{encode, decode}; + +#[derive(Debug, PartialEq, RlpEncodable, RlpDecodable)] +struct Foo { + a: String, +} + +#[derive(Debug, PartialEq, RlpEncodableWrapper, RlpDecodableWrapper)] +struct FooWrapper { + a: String, +} + +#[test] +fn test_encode_foo() { + let foo = Foo { + a: "cat".into(), + }; + + let expected = vec![0xc4, 0x83, b'c', b'a', b't']; + let out = encode(&foo).into_vec(); + assert_eq!(out, expected); + + let decoded = decode(&expected); + assert_eq!(foo, decoded); +} + +#[test] +fn test_encode_foo_wrapper() { + let foo = FooWrapper { + a: "cat".into(), + }; + + let expected = vec![0x83, b'c', b'a', b't']; + let out = encode(&foo).into_vec(); + assert_eq!(out, expected); + + let decoded = decode(&expected); + assert_eq!(foo, decoded); +} +