From 044d070667c924652ec6c5997eadd0d30e538afb Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 22 Mar 2017 14:41:46 +0100 Subject: [PATCH] rlp deserialization refactor, 30% faster (#4901) * fixed naming of rlp modules * RlpStream cleanup * appending short rlp lists (0...55 bytes) is 25% faster * RlpStream does not use bytes module, nor trait Stream * removed unused code from rlp module * compiling ethcore-util with new rlp serialization * compiling parity with new rlp serialization * fixed compiling ethcore-light with new rlp serialization * fixed compiling ethsync with new rlp serialization * moved rlp benches and rlp tests * rlp deserialization refactor, 30% faster * removed redundant comment, print * fixed compiling parity with new rlp deserialization * removed redundant double-space * fixed failing test * updated rlp docs, removed unused traits * fixed rlp benchmarks * replace usage of WriteBytesExt with ByteOrder * removed unused, commented out code * fixed merge conflict --- ethcore/light/src/cht.rs | 2 +- ethcore/light/src/net/mod.rs | 4 +- ethcore/light/src/net/request_credits.rs | 6 +- ethcore/light/src/net/status.rs | 10 +- ethcore/light/src/on_demand/request.rs | 2 +- ethcore/src/block.rs | 15 +- ethcore/src/blockchain/extras.rs | 22 ++- ethcore/src/blooms/bloom.rs | 4 +- ethcore/src/blooms/bloom_group.rs | 4 +- ethcore/src/client/client.rs | 4 +- ethcore/src/engines/authority_round.rs | 2 +- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/tendermint/message.rs | 9 +- ethcore/src/engines/tendermint/mod.rs | 2 +- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/header.rs | 6 +- ethcore/src/json_tests/transaction.rs | 2 +- ethcore/src/migrations/blocks/v8.rs | 2 +- ethcore/src/migrations/state/v7.rs | 5 +- ethcore/src/migrations/v9.rs | 2 +- ethcore/src/snapshot/account.rs | 4 +- ethcore/src/snapshot/block.rs | 8 +- ethcore/src/snapshot/io.rs | 16 +- ethcore/src/snapshot/mod.rs | 10 +- ethcore/src/spec/spec.rs | 2 +- ethcore/src/state/account.rs | 2 +- ethcore/src/tests/client.rs | 1 - ethcore/src/trace/bloom.rs | 8 +- ethcore/src/types/basic_account.rs | 3 +- ethcore/src/types/encoded.rs | 2 +- ethcore/src/types/executed.rs | 4 +- ethcore/src/types/log_entry.rs | 9 +- ethcore/src/types/receipt.rs | 19 +- ethcore/src/types/snapshot_manifest.rs | 4 +- ethcore/src/types/trace_types/error.rs | 6 +- ethcore/src/types/trace_types/flat.rs | 13 +- ethcore/src/types/trace_types/trace.rs | 122 ++++++------- ethcore/src/types/transaction.rs | 10 +- ethcore/src/verification/verification.rs | 5 +- ethcore/src/views/block.rs | 6 +- ethcore/src/views/body.rs | 6 +- ethcore/src/views/header.rs | 2 +- ethcore/src/views/transaction.rs | 2 +- local-store/src/lib.rs | 2 +- parity/informant.rs | 1 - rpc/src/v1/impls/eth.rs | 2 +- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/impls/signer.rs | 2 +- rpc/src/v1/impls/traces.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 2 +- sync/src/block_sync.rs | 6 +- sync/src/chain.rs | 24 +-- sync/src/light_sync/response.rs | 2 +- util/network/src/discovery.rs | 2 +- util/network/src/session.rs | 9 +- util/{ => rlp}/benches/rlp.rs | 20 +-- util/rlp/src/bytes.rs | 148 ---------------- util/rlp/src/compression.rs | 8 +- util/rlp/src/error.rs | 9 - util/rlp/src/impls.rs | 159 ++++++++++++++++- util/rlp/src/lib.rs | 19 +- util/rlp/src/rlpin.rs | 201 ++++++++++++++++----- util/rlp/src/traits.rs | 204 +--------------------- util/rlp/src/untrusted_rlp.rs | 185 +++++--------------- util/rlp/{src => tests}/tests.rs | 56 +++--- util/src/journaldb/earlymergedb.rs | 6 +- util/src/journaldb/overlayrecentdb.rs | 2 +- util/src/journaldb/refcounteddb.rs | 2 +- util/src/kvdb.rs | 2 +- util/src/trie/lookup.rs | 2 +- util/src/trie/triedbmut.rs | 2 +- 71 files changed, 618 insertions(+), 834 deletions(-) rename util/{ => rlp}/benches/rlp.rs (85%) delete mode 100644 util/rlp/src/bytes.rs rename util/rlp/{src => tests}/tests.rs (90%) diff --git a/ethcore/light/src/cht.rs b/ethcore/light/src/cht.rs index 94b9946c0..7c749b44f 100644 --- a/ethcore/light/src/cht.rs +++ b/ethcore/light/src/cht.rs @@ -23,7 +23,7 @@ use ethcore::ids::BlockId; use util::{Bytes, H256, U256, HashDB, MemoryDB}; use util::trie::{self, TrieMut, TrieDBMut, Trie, TrieDB, Recorder}; -use rlp::{RlpStream, UntrustedRlp, View}; +use rlp::{RlpStream, UntrustedRlp}; // encode a key. macro_rules! key { diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index 4749dc281..3830dde4b 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -24,7 +24,7 @@ use ethcore::receipt::Receipt; use io::TimerToken; use network::{NetworkProtocolHandler, NetworkContext, PeerId}; -use rlp::{RlpStream, UntrustedRlp, View}; +use rlp::{RlpStream, UntrustedRlp}; use util::hash::H256; use util::{Bytes, DBValue, Mutex, RwLock, U256}; use time::{Duration, SteadyTime}; @@ -953,7 +953,7 @@ impl LightProtocol { let id_guard = self.pre_verify_response(peer, request::Kind::Receipts, &raw)?; let raw_receipts: Vec> = raw.at(2)? .iter() - .map(|x| x.as_val()) + .map(|x| x.as_list()) .collect::>()?; let req_id = id_guard.defuse(); diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index 7f1960fc5..f35c6662f 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -126,10 +126,8 @@ impl Encodable for CostTable { } } -impl RlpDecodable for CostTable { - fn decode(decoder: &D) -> Result where D: Decoder { - let rlp = decoder.as_rlp(); - +impl Decodable for CostTable { + fn decode(rlp: &UntrustedRlp) -> Result { let mut headers = None; let mut bodies = None; let mut receipts = None; diff --git a/ethcore/light/src/net/status.rs b/ethcore/light/src/net/status.rs index f5464c036..732826430 100644 --- a/ethcore/light/src/net/status.rs +++ b/ethcore/light/src/net/status.rs @@ -16,7 +16,7 @@ //! Peer status and capabilities. -use rlp::{DecoderError, RlpDecodable, Encodable, RlpStream, UntrustedRlp, View}; +use rlp::{DecoderError, Encodable, Decodable, RlpStream, UntrustedRlp}; use util::{H256, U256}; use super::request_credits::FlowParams; @@ -91,7 +91,7 @@ struct Parser<'a> { impl<'a> Parser<'a> { // expect a specific next key, and decode the value. // error on unexpected key or invalid value. - fn expect(&mut self, key: Key) -> Result { + fn expect(&mut self, key: Key) -> Result { self.expect_raw(key).and_then(|item| item.as_val()) } @@ -110,7 +110,7 @@ impl<'a> Parser<'a> { // get the next key and value RLP. fn get_next(&mut self) -> Result)>, DecoderError> { - while self.pos < self.rlp.item_count() { + while self.pos < self.rlp.item_count()? { let pair = self.rlp.at(self.pos)?; let k: String = pair.val_at(0)?; @@ -374,7 +374,7 @@ mod tests { use super::*; use super::super::request_credits::FlowParams; use util::{U256, H256}; - use rlp::{RlpStream, UntrustedRlp, View}; + use rlp::{RlpStream, UntrustedRlp}; #[test] fn full_handshake() { @@ -474,7 +474,7 @@ mod tests { let handshake = write_handshake(&status, &capabilities, Some(&flow_params)); let interleaved = { let handshake = UntrustedRlp::new(&handshake); - let mut stream = RlpStream::new_list(handshake.item_count() * 3); + let mut stream = RlpStream::new_list(handshake.item_count().unwrap_or(0) * 3); for item in handshake.iter() { stream.append_raw(item.as_raw(), 1); diff --git a/ethcore/light/src/on_demand/request.rs b/ethcore/light/src/on_demand/request.rs index 0b16d091c..1db796982 100644 --- a/ethcore/light/src/on_demand/request.rs +++ b/ethcore/light/src/on_demand/request.rs @@ -26,7 +26,7 @@ use ethcore::receipt::Receipt; use ethcore::state::{self, ProvedExecution}; use ethcore::transaction::SignedTransaction; -use rlp::{RlpStream, UntrustedRlp, View}; +use rlp::{RlpStream, UntrustedRlp}; use util::{Address, Bytes, DBValue, HashDB, H256, U256}; use util::memorydb::MemoryDB; use util::sha3::Hashable; diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index c0ae90bb4..38278af05 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -20,7 +20,7 @@ use std::cmp; use std::sync::Arc; use std::collections::HashSet; -use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, Decoder, DecoderError, View}; +use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; use util::{Bytes, Address, Uint, Hashable, U256, H256, ordered_trie_root, SHA3_NULL_RLP}; use util::error::{Mismatch, OutOfBounds}; @@ -67,18 +67,17 @@ impl Block { impl Decodable for Block { - fn decode(decoder: &D) -> Result where D: Decoder { - if decoder.as_raw().len() != decoder.as_rlp().payload_info()?.total() { + fn decode(rlp: &UntrustedRlp) -> Result { + if rlp.as_raw().len() != rlp.payload_info()?.total() { return Err(DecoderError::RlpIsTooBig); } - let d = decoder.as_rlp(); - if d.item_count() != 3 { + if rlp.item_count()? != 3 { return Err(DecoderError::RlpIncorrectListLen); } Ok(Block { - header: d.val_at(0)?, - transactions: d.val_at(1)?, - uncles: d.val_at(2)?, + header: rlp.val_at(0)?, + transactions: rlp.list_at(1)?, + uncles: rlp.list_at(2)?, }) } } diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 3122a78d7..0c8616a45 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -154,13 +154,12 @@ impl HeapSizeOf for BlockDetails { } impl Decodable for BlockDetails { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let details = BlockDetails { - number: d.val_at(0)?, - total_difficulty: d.val_at(1)?, - parent: d.val_at(2)?, - children: d.val_at(3)?, + number: rlp.val_at(0)?, + total_difficulty: rlp.val_at(1)?, + parent: rlp.val_at(2)?, + children: rlp.list_at(3)?, }; Ok(details) } @@ -190,11 +189,10 @@ impl HeapSizeOf for TransactionAddress { } impl Decodable for TransactionAddress { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let tx_address = TransactionAddress { - block_hash: d.val_at(0)?, - index: d.val_at(1)?, + block_hash: rlp.val_at(0)?, + index: rlp.val_at(1)?, }; Ok(tx_address) @@ -224,9 +222,9 @@ impl BlockReceipts { } impl Decodable for BlockReceipts { - fn decode(decoder: &D) -> Result where D: Decoder { + fn decode(rlp: &UntrustedRlp) -> Result { Ok(BlockReceipts { - receipts: Decodable::decode(decoder)? + receipts: rlp.as_list()?, }) } } diff --git a/ethcore/src/blooms/bloom.rs b/ethcore/src/blooms/bloom.rs index a3584f739..cac9ff448 100644 --- a/ethcore/src/blooms/bloom.rs +++ b/ethcore/src/blooms/bloom.rs @@ -44,8 +44,8 @@ impl Into for Bloom { } impl Decodable for Bloom { - fn decode(decoder: &D) -> Result where D: Decoder { - Decodable::decode(decoder).map(Bloom) + fn decode(rlp: &UntrustedRlp) -> Result { + LogBloom::decode(rlp).map(Bloom) } } diff --git a/ethcore/src/blooms/bloom_group.rs b/ethcore/src/blooms/bloom_group.rs index 6d8c40f75..087f20b6f 100644 --- a/ethcore/src/blooms/bloom_group.rs +++ b/ethcore/src/blooms/bloom_group.rs @@ -52,8 +52,8 @@ impl Into for BloomGroup { } impl Decodable for BloomGroup { - fn decode(decoder: &D) -> Result where D: Decoder { - let blooms = Decodable::decode(decoder)?; + fn decode(rlp: &UntrustedRlp) -> Result { + let blooms = rlp.as_list()?; let group = BloomGroup { blooms: blooms }; diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 06889a538..d284954e7 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -66,7 +66,7 @@ use evm::{Factory as EvmFactory, Schedule}; use miner::{Miner, MinerService, TransactionImportResult}; use snapshot::{self, io as snapshot_io}; use factory::Factories; -use rlp::{View, UntrustedRlp}; +use rlp::UntrustedRlp; use state_db::StateDB; use rand::OsRng; use client::registry::Registry; @@ -539,7 +539,7 @@ impl Client { )?; // Commit results - let receipts = ::rlp::decode(&receipts_bytes); + let receipts = ::rlp::decode_list(&receipts_bytes); let mut batch = DBTransaction::new(); chain.insert_unordered_block(&mut batch, &block_bytes, receipts, None, false, true); // Final commit to the DB diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index 03b5d785f..2a18c748d 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -21,7 +21,7 @@ use std::sync::Weak; use std::time::{UNIX_EPOCH, Duration}; use util::*; use ethkey::{verify_address, Signature}; -use rlp::{UntrustedRlp, View, encode}; +use rlp::{UntrustedRlp, encode}; use account_provider::AccountProvider; use block::*; use spec::CommonParams; diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 34b89b2d6..d8a1df947 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -138,7 +138,7 @@ impl Engine for BasicAuthority { } fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { - use rlp::{UntrustedRlp, View}; + use rlp::UntrustedRlp; // Check if the signature belongs to a validator, can depend on parent state. let sig = UntrustedRlp::new(&header.seal()[0]).as_val::()?; let signer = public_to_address(&recover(&sig.into(), &header.bare_hash())?); diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index ead58ba98..0649ea050 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -20,7 +20,7 @@ use util::*; use super::{Height, View, BlockHash, Step}; use error::Error; use header::Header; -use rlp::{Rlp, UntrustedRlp, RlpStream, Encodable, Decodable, Decoder, DecoderError, View as RlpView}; +use rlp::{Rlp, UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; use ethkey::{recover, public_to_address}; use super::super::vote_collector::Message; @@ -150,8 +150,8 @@ impl Step { } impl Decodable for Step { - fn decode(decoder: &D) -> Result where D: Decoder { - match decoder.as_rlp().as_val()? { + fn decode(rlp: &UntrustedRlp) -> Result { + match rlp.as_val()? { 0u8 => Ok(Step::Propose), 1 => Ok(Step::Prevote), 2 => Ok(Step::Precommit), @@ -168,8 +168,7 @@ impl Encodable for Step { /// (signature, (height, view, step, block_hash)) impl Decodable for ConsensusMessage { - fn decode(decoder: &D) -> Result where D: Decoder { - let rlp = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let m = rlp.at(1)?; let block_message: H256 = m.val_at(3)?; Ok(ConsensusMessage { diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 2d2714e97..46e67a2a8 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -33,7 +33,7 @@ use error::{Error, BlockError}; use header::Header; use builtin::Builtin; use env_info::EnvInfo; -use rlp::{UntrustedRlp, View as RlpView}; +use rlp::UntrustedRlp; use ethkey::{recover, public_to_address, Signature}; use account_provider::AccountProvider; use block::*; diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index fbb9c8a5c..b1907971c 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -27,7 +27,7 @@ use transaction::UnverifiedTransaction; use engines::Engine; use evm::Schedule; use ethjson; -use rlp::{self, UntrustedRlp, View}; +use rlp::{self, UntrustedRlp}; /// Parity tries to round block.gas_limit to multiple of this constant pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]); diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 60b9dcb46..4517c5764 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -261,9 +261,7 @@ impl Header { } impl Decodable for Header { - fn decode(decoder: &D) -> Result where D: Decoder { - let r = decoder.as_rlp(); - + fn decode(r: &UntrustedRlp) -> Result { let mut blockheader = Header { parent_hash: r.val_at(0)?, uncles_hash: r.val_at(1)?, @@ -283,7 +281,7 @@ impl Decodable for Header { bare_hash: RefCell::new(None), }; - for i in 13..r.item_count() { + for i in 13..r.item_count()? { blockheader.seal.push(r.at(i)?.as_raw().to_vec()) } diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index 5c8ac710a..f400180ee 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -17,7 +17,7 @@ use super::test_common::*; use evm; use ethjson; -use rlp::{UntrustedRlp, View}; +use rlp::UntrustedRlp; use transaction::{Action, UnverifiedTransaction}; use ethstore::ethkey::public_to_address; diff --git a/ethcore/src/migrations/blocks/v8.rs b/ethcore/src/migrations/blocks/v8.rs index 2c1d955e0..2514db702 100644 --- a/ethcore/src/migrations/blocks/v8.rs +++ b/ethcore/src/migrations/blocks/v8.rs @@ -17,7 +17,7 @@ //! This migration compresses the state db. use util::migration::{SimpleMigration, Progress}; -use rlp::{Compressible, UntrustedRlp, View, RlpType}; +use rlp::{Compressible, UntrustedRlp, RlpType}; /// Compressing migration. #[derive(Default)] diff --git a/ethcore/src/migrations/state/v7.rs b/ethcore/src/migrations/state/v7.rs index 9e2d3c110..e9da80c31 100644 --- a/ethcore/src/migrations/state/v7.rs +++ b/ethcore/src/migrations/state/v7.rs @@ -26,8 +26,7 @@ use util::migration::{Batch, Config, Error, Migration, SimpleMigration, Progress use util::sha3::Hashable; use std::sync::Arc; -use rlp::{decode, Rlp, RlpStream, View}; - +use rlp::{decode, Rlp, RlpStream}; // attempt to migrate a key, value pair. None if migration not possible. fn attempt_migrate(mut key_h: H256, val: &[u8]) -> Option { @@ -184,7 +183,7 @@ impl OverlayRecentV7 { } // migrate all deleted keys. - let mut deleted_keys: Vec = rlp.val_at(2); + let mut deleted_keys: Vec = rlp.list_at(2); for old_key in &mut deleted_keys { if let Some(new) = self.migrated_keys.get(&*old_key) { *old_key = new.clone(); diff --git a/ethcore/src/migrations/v9.rs b/ethcore/src/migrations/v9.rs index 7e469fb7b..9a6eb5088 100644 --- a/ethcore/src/migrations/v9.rs +++ b/ethcore/src/migrations/v9.rs @@ -17,7 +17,7 @@ //! This migration consolidates all databases into single one using Column Families. -use rlp::{Rlp, RlpStream, View}; +use rlp::{Rlp, RlpStream}; use util::kvdb::Database; use util::migration::{Batch, Config, Error, Migration, Progress}; use std::sync::Arc; diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index 62ee28f89..c086b5c44 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -22,7 +22,7 @@ use snapshot::Error; use util::{U256, H256, Bytes, HashDB, SHA3_EMPTY, SHA3_NULL_RLP}; use util::trie::{TrieDB, Trie}; -use rlp::{RlpStream, UntrustedRlp, View}; +use rlp::{RlpStream, UntrustedRlp}; use std::collections::HashSet; @@ -180,7 +180,7 @@ mod tests { use util::sha3::{SHA3_EMPTY, SHA3_NULL_RLP}; use util::{Address, H256, HashDB, DBValue}; - use rlp::{UntrustedRlp, View}; + use rlp::UntrustedRlp; use std::collections::HashSet; diff --git a/ethcore/src/snapshot/block.rs b/ethcore/src/snapshot/block.rs index 0eee05575..b5144b23d 100644 --- a/ethcore/src/snapshot/block.rs +++ b/ethcore/src/snapshot/block.rs @@ -20,7 +20,7 @@ use block::Block; use header::Header; use views::BlockView; -use rlp::{DecoderError, RlpStream, UntrustedRlp, View}; +use rlp::{DecoderError, RlpStream, UntrustedRlp}; use util::{Bytes, Hashable, H256}; use util::triehash::ordered_trie_root; @@ -101,8 +101,8 @@ impl AbridgedBlock { header.set_timestamp(rlp.val_at(6)?); header.set_extra_data(rlp.val_at(7)?); - let transactions = rlp.val_at(8)?; - let uncles: Vec
= rlp.val_at(9)?; + let transactions = rlp.list_at(8)?; + let uncles: Vec
= rlp.list_at(9)?; header.set_transactions_root(ordered_trie_root( rlp.at(8)?.iter().map(|r| r.as_raw().to_owned()) @@ -114,7 +114,7 @@ impl AbridgedBlock { header.set_uncles_hash(uncles_rlp.as_raw().sha3()); let mut seal_fields = Vec::new(); - for i in (HEADER_FIELDS + BLOCK_FIELDS)..rlp.item_count() { + for i in (HEADER_FIELDS + BLOCK_FIELDS)..rlp.item_count()? { let seal_rlp = rlp.at(i)?; seal_fields.push(seal_rlp.as_raw().to_owned()); } diff --git a/ethcore/src/snapshot/io.rs b/ethcore/src/snapshot/io.rs index 45f3ec4df..e8f11efd1 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, View}; +use rlp::{self, Encodable, RlpStream, UntrustedRlp}; use super::ManifestData; @@ -57,12 +57,10 @@ impl Encodable for ChunkInfo { } impl rlp::Decodable for ChunkInfo { - fn decode(decoder: &D) -> Result { - let d = decoder.as_rlp(); - - let hash = d.val_at(0)?; - let len = d.val_at(1)?; - let off = d.val_at(2)?; + 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)) } } @@ -257,8 +255,8 @@ impl PackedReader { let rlp = UntrustedRlp::new(&manifest_buf); - let state: Vec = rlp.val_at(0)?; - let blocks: Vec = rlp.val_at(1)?; + let state: Vec = rlp.list_at(0)?; + let blocks: Vec = rlp.list_at(1)?; let manifest = ManifestData { state_hashes: state.iter().map(|c| c.0).collect(), diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 473c91e4d..d496139ff 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -37,7 +37,7 @@ use util::journaldb::{self, Algorithm, JournalDB}; use util::kvdb::Database; use util::trie::{TrieDB, TrieDBMut, Trie, TrieMut}; use util::sha3::SHA3_NULL_RLP; -use rlp::{RlpStream, UntrustedRlp, View}; +use rlp::{RlpStream, UntrustedRlp}; use bloom_journal::Bloom; use self::block::AbridgedBlock; @@ -408,10 +408,10 @@ impl StateRebuilder { pub fn feed(&mut self, chunk: &[u8], flag: &AtomicBool) -> Result<(), ::error::Error> { let rlp = UntrustedRlp::new(chunk); let empty_rlp = StateAccount::new_basic(U256::zero(), U256::zero()).rlp(); - let mut pairs = Vec::with_capacity(rlp.item_count()); + let mut pairs = Vec::with_capacity(rlp.item_count()?); // initialize the pairs vector with empty values so we have slots to write into. - pairs.resize(rlp.item_count(), (H256::new(), Vec::new())); + pairs.resize(rlp.item_count()?, (H256::new(), Vec::new())); let status = rebuild_accounts( self.db.as_hashdb_mut(), @@ -601,7 +601,7 @@ impl BlockRebuilder { use util::triehash::ordered_trie_root; let rlp = UntrustedRlp::new(chunk); - let item_count = rlp.item_count(); + let item_count = rlp.item_count()?; let num_blocks = (item_count - 3) as u64; trace!(target: "snapshot", "restoring block chunk with {} blocks.", item_count - 3); @@ -621,7 +621,7 @@ impl BlockRebuilder { let pair = rlp.at(idx)?; let abridged_rlp = pair.at(0)?.as_raw().to_owned(); let abridged_block = AbridgedBlock::from_raw(abridged_rlp); - let receipts: Vec<::receipt::Receipt> = pair.val_at(1)?; + let receipts: Vec<::receipt::Receipt> = pair.list_at(1)?; let receipts_root = ordered_trie_root( pair.at(1)?.iter().map(|r| r.as_raw().to_owned()) ); diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 76eefa3a6..21c07c9a3 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -34,7 +34,7 @@ use super::genesis::Genesis; use super::seal::Generic as GenericSeal; use ethereum; use ethjson; -use rlp::{Rlp, RlpStream, View}; +use rlp::{Rlp, RlpStream}; /// Parameters common to all engines. #[derive(Debug, PartialEq, Clone, Default)] diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index ebdf36d89..9e762979b 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -461,7 +461,7 @@ impl fmt::Debug for Account { #[cfg(test)] mod tests { - use rlp::{UntrustedRlp, RlpType, View, Compressible}; + use rlp::{UntrustedRlp, RlpType, Compressible}; use util::*; use super::*; use account_db::*; diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 3734c5520..e61edd478 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -25,7 +25,6 @@ use types::filter::Filter; use util::*; use devtools::*; use miner::Miner; -use rlp::View; use spec::Spec; use views::BlockView; use ethkey::{KeyPair, Secret}; diff --git a/ethcore/src/trace/bloom.rs b/ethcore/src/trace/bloom.rs index e0a32d5ae..561a83719 100644 --- a/ethcore/src/trace/bloom.rs +++ b/ethcore/src/trace/bloom.rs @@ -60,8 +60,8 @@ impl Into for BlockTracesBloomGroup { } impl Decodable for BlockTracesBloom { - fn decode(decoder: &D) -> Result where D: Decoder { - Decodable::decode(decoder).map(BlockTracesBloom) + fn decode(rlp: &UntrustedRlp) -> Result { + LogBloom::decode(rlp).map(BlockTracesBloom) } } @@ -72,8 +72,8 @@ impl Encodable for BlockTracesBloom { } impl Decodable for BlockTracesBloomGroup { - fn decode(decoder: &D) -> Result where D: Decoder { - let blooms = Decodable::decode(decoder)?; + fn decode(rlp: &UntrustedRlp) -> Result { + let blooms = rlp.as_list()?; let group = BlockTracesBloomGroup { blooms: blooms }; diff --git a/ethcore/src/types/basic_account.rs b/ethcore/src/types/basic_account.rs index de091827f..c071040cf 100644 --- a/ethcore/src/types/basic_account.rs +++ b/ethcore/src/types/basic_account.rs @@ -43,8 +43,7 @@ impl Encodable for BasicAccount { } impl Decodable for BasicAccount { - fn decode(decoder: &D) -> Result where D: Decoder { - let rlp = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { Ok(BasicAccount { nonce: rlp.val_at(0)?, balance: rlp.val_at(1)?, diff --git a/ethcore/src/types/encoded.rs b/ethcore/src/types/encoded.rs index 49f83f0b7..0a4164044 100644 --- a/ethcore/src/types/encoded.rs +++ b/ethcore/src/types/encoded.rs @@ -29,7 +29,7 @@ use transaction::UnverifiedTransaction; use views; use util::{Address, Hashable, H256, H2048, U256, HeapSizeOf}; -use rlp::{Rlp, View}; +use rlp::Rlp; /// Owning header view. #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/ethcore/src/types/executed.rs b/ethcore/src/types/executed.rs index 4301044ce..f18bd1bee 100644 --- a/ethcore/src/types/executed.rs +++ b/ethcore/src/types/executed.rs @@ -51,8 +51,8 @@ impl Encodable for CallType { } impl Decodable for CallType { - fn decode(decoder: &D) -> Result where D: Decoder { - decoder.as_rlp().as_val().and_then(|v| Ok(match v { + fn decode(rlp: &UntrustedRlp) -> Result { + rlp.as_val().and_then(|v| Ok(match v { 0u32 => CallType::None, 1 => CallType::Call, 2 => CallType::CallCode, diff --git a/ethcore/src/types/log_entry.rs b/ethcore/src/types/log_entry.rs index 3eac1dad5..f3260c114 100644 --- a/ethcore/src/types/log_entry.rs +++ b/ethcore/src/types/log_entry.rs @@ -47,12 +47,11 @@ impl Encodable for LogEntry { } impl Decodable for LogEntry { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let entry = LogEntry { - address: d.val_at(0)?, - topics: d.val_at(1)?, - data: d.val_at(2)?, + address: rlp.val_at(0)?, + topics: rlp.list_at(1)?, + data: rlp.val_at(2)?, }; Ok(entry) } diff --git a/ethcore/src/types/receipt.rs b/ethcore/src/types/receipt.rs index 5db74b0b6..fc082d40b 100644 --- a/ethcore/src/types/receipt.rs +++ b/ethcore/src/types/receipt.rs @@ -65,21 +65,20 @@ impl Encodable for Receipt { } impl Decodable for Receipt { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); - if d.item_count() == 3 { + fn decode(rlp: &UntrustedRlp) -> Result { + if rlp.item_count()? == 3 { Ok(Receipt { state_root: None, - gas_used: d.val_at(0)?, - log_bloom: d.val_at(1)?, - logs: d.val_at(2)?, + gas_used: rlp.val_at(0)?, + log_bloom: rlp.val_at(1)?, + logs: rlp.list_at(2)?, }) } else { Ok(Receipt { - state_root: Some(d.val_at(0)?), - gas_used: d.val_at(1)?, - log_bloom: d.val_at(2)?, - logs: d.val_at(3)?, + state_root: Some(rlp.val_at(0)?), + gas_used: rlp.val_at(1)?, + log_bloom: rlp.val_at(2)?, + logs: rlp.list_at(3)?, }) } } diff --git a/ethcore/src/types/snapshot_manifest.rs b/ethcore/src/types/snapshot_manifest.rs index 910a038bd..84ca05822 100644 --- a/ethcore/src/types/snapshot_manifest.rs +++ b/ethcore/src/types/snapshot_manifest.rs @@ -53,8 +53,8 @@ impl ManifestData { pub fn from_rlp(raw: &[u8]) -> Result { let decoder = UntrustedRlp::new(raw); - let state_hashes: Vec = decoder.val_at(0)?; - let block_hashes: Vec = decoder.val_at(1)?; + let state_hashes: Vec = decoder.list_at(0)?; + let block_hashes: Vec = decoder.list_at(1)?; let state_root: H256 = decoder.val_at(2)?; let block_number: u64 = decoder.val_at(3)?; let block_hash: H256 = decoder.val_at(4)?; diff --git a/ethcore/src/types/trace_types/error.rs b/ethcore/src/types/trace_types/error.rs index 33ccf2bb7..58657d7aa 100644 --- a/ethcore/src/types/trace_types/error.rs +++ b/ethcore/src/types/trace_types/error.rs @@ -17,7 +17,7 @@ //! Trace errors. use std::fmt; -use rlp::{Encodable, RlpStream, Decodable, Decoder, DecoderError, View}; +use rlp::{Encodable, RlpStream, Decodable, DecoderError, UntrustedRlp}; use evm::Error as EvmError; /// Trace evm errors. @@ -91,9 +91,9 @@ impl Encodable for Error { } impl Decodable for Error { - fn decode(decoder: &D) -> Result where D: Decoder { + fn decode(rlp: &UntrustedRlp) -> Result { use self::Error::*; - let value: u8 = decoder.as_rlp().as_val()?; + let value: u8 = rlp.as_val()?; match value { 0 => Ok(OutOfGas), 1 => Ok(BadJumpDestination), diff --git a/ethcore/src/types/trace_types/flat.rs b/ethcore/src/types/trace_types/flat.rs index 832e7d055..90b770beb 100644 --- a/ethcore/src/types/trace_types/flat.rs +++ b/ethcore/src/types/trace_types/flat.rs @@ -64,9 +64,8 @@ impl Encodable for FlatTrace { } impl Decodable for FlatTrace { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); - let v: Vec = d.val_at(3)?; + fn decode(d: &UntrustedRlp) -> Result { + let v: Vec = d.list_at(3)?; let res = FlatTrace { action: d.val_at(0)?, result: d.val_at(1)?, @@ -108,8 +107,8 @@ impl Encodable for FlatTransactionTraces { } impl Decodable for FlatTransactionTraces { - fn decode(decoder: &D) -> Result where D: Decoder { - Ok(FlatTransactionTraces(Decodable::decode(decoder)?)) + fn decode(rlp: &UntrustedRlp) -> Result { + Ok(FlatTransactionTraces(rlp.as_list()?)) } } @@ -149,8 +148,8 @@ impl Encodable for FlatBlockTraces { } impl Decodable for FlatBlockTraces { - fn decode(decoder: &D) -> Result where D: Decoder { - Ok(FlatBlockTraces(Decodable::decode(decoder)?)) + fn decode(rlp: &UntrustedRlp) -> Result { + Ok(FlatBlockTraces(rlp.as_list()?)) } } diff --git a/ethcore/src/types/trace_types/trace.rs b/ethcore/src/types/trace_types/trace.rs index 9c3377dac..ed5dfb9f1 100644 --- a/ethcore/src/types/trace_types/trace.rs +++ b/ethcore/src/types/trace_types/trace.rs @@ -45,11 +45,10 @@ impl Encodable for CallResult { } impl Decodable for CallResult { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let res = CallResult { - gas_used: d.val_at(0)?, - output: d.val_at(1)?, + gas_used: rlp.val_at(0)?, + output: rlp.val_at(1)?, }; Ok(res) @@ -78,12 +77,11 @@ impl Encodable for CreateResult { } impl Decodable for CreateResult { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let res = CreateResult { - gas_used: d.val_at(0)?, - code: d.val_at(1)?, - address: d.val_at(2)?, + gas_used: rlp.val_at(0)?, + code: rlp.val_at(1)?, + address: rlp.val_at(2)?, }; Ok(res) @@ -141,15 +139,14 @@ impl Encodable for Call { } impl Decodable for Call { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let res = Call { - from: d.val_at(0)?, - to: d.val_at(1)?, - value: d.val_at(2)?, - gas: d.val_at(3)?, - input: d.val_at(4)?, - call_type: d.val_at(5)?, + 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) @@ -201,13 +198,12 @@ impl Encodable for Create { } impl Decodable for Create { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let res = Create { - from: d.val_at(0)?, - value: d.val_at(1)?, - gas: d.val_at(2)?, - init: d.val_at(3)?, + from: rlp.val_at(0)?, + value: rlp.val_at(1)?, + gas: rlp.val_at(2)?, + init: rlp.val_at(3)?, }; Ok(res) @@ -252,12 +248,11 @@ impl Encodable for Suicide { } impl Decodable for Suicide { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let res = Suicide { - address: d.val_at(0)?, - refund_address: d.val_at(1)?, - balance: d.val_at(2)?, + address: rlp.val_at(0)?, + refund_address: rlp.val_at(1)?, + balance: rlp.val_at(2)?, }; Ok(res) @@ -298,13 +293,12 @@ impl Encodable for Action { } impl Decodable for Action { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); - let action_type: u8 = d.val_at(0)?; + fn decode(rlp: &UntrustedRlp) -> Result { + let action_type: u8 = rlp.val_at(0)?; match action_type { - 0 => d.val_at(1).map(Action::Call), - 1 => d.val_at(1).map(Action::Create), - 2 => d.val_at(1).map(Action::Suicide), + 0 => rlp.val_at(1).map(Action::Call), + 1 => rlp.val_at(1).map(Action::Create), + 2 => rlp.val_at(1).map(Action::Suicide), _ => Err(DecoderError::Custom("Invalid action type.")), } } @@ -369,14 +363,13 @@ impl Encodable for Res { } impl Decodable for Res { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); - let action_type: u8 = d.val_at(0)?; + fn decode(rlp: &UntrustedRlp) -> Result { + let action_type: u8 = rlp.val_at(0)?; match action_type { - 0 => d.val_at(1).map(Res::Call), - 1 => d.val_at(1).map(Res::Create), - 2 => d.val_at(1).map(Res::FailedCall), - 3 => d.val_at(1).map(Res::FailedCreate), + 0 => rlp.val_at(1).map(Res::Call), + 1 => rlp.val_at(1).map(Res::Create), + 2 => rlp.val_at(1).map(Res::FailedCall), + 3 => rlp.val_at(1).map(Res::FailedCreate), 4 => Ok(Res::None), _ => Err(DecoderError::Custom("Invalid result type.")), } @@ -420,11 +413,10 @@ impl Encodable for MemoryDiff { } impl Decodable for MemoryDiff { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { Ok(MemoryDiff { - offset: d.val_at(0)?, - data: d.val_at(1)?, + offset: rlp.val_at(0)?, + data: rlp.val_at(1)?, }) } } @@ -448,11 +440,10 @@ impl Encodable for StorageDiff { } impl Decodable for StorageDiff { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { Ok(StorageDiff { - location: d.val_at(0)?, - value: d.val_at(1)?, + location: rlp.val_at(0)?, + value: rlp.val_at(1)?, }) } } @@ -482,13 +473,12 @@ impl Encodable for VMExecutedOperation { } impl Decodable for VMExecutedOperation { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { Ok(VMExecutedOperation { - gas_used: d.val_at(0)?, - stack_push: d.val_at(1)?, - mem_diff: d.val_at(2)?, - store_diff: d.val_at(3)?, + gas_used: rlp.val_at(0)?, + stack_push: rlp.list_at(1)?, + mem_diff: rlp.val_at(2)?, + store_diff: rlp.val_at(3)?, }) } } @@ -518,13 +508,12 @@ impl Encodable for VMOperation { } impl Decodable for VMOperation { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let res = VMOperation { - pc: d.val_at(0)?, - instruction: d.val_at(1)?, - gas_cost: d.val_at(2)?, - executed: d.val_at(3)?, + pc: rlp.val_at(0)?, + instruction: rlp.val_at(1)?, + gas_cost: rlp.val_at(2)?, + executed: rlp.val_at(3)?, }; Ok(res) @@ -557,13 +546,12 @@ impl Encodable for VMTrace { } impl Decodable for VMTrace { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { let res = VMTrace { - parent_step: d.val_at(0)?, - code: d.val_at(1)?, - operations: d.val_at(2)?, - subs: d.val_at(3)?, + 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/types/transaction.rs b/ethcore/src/types/transaction.rs index 506bf001e..79e27d97d 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -42,8 +42,7 @@ impl Default for Action { } impl Decodable for Action { - fn decode(decoder: &D) -> Result where D: Decoder { - let rlp = decoder.as_rlp(); + fn decode(rlp: &UntrustedRlp) -> Result { if rlp.is_empty() { Ok(Action::Create) } else { @@ -243,12 +242,11 @@ impl Deref for UnverifiedTransaction { } impl Decodable for UnverifiedTransaction { - fn decode(decoder: &D) -> Result where D: Decoder { - let d = decoder.as_rlp(); - if d.item_count() != 9 { + fn decode(d: &UntrustedRlp) -> Result { + if d.item_count()? != 9 { return Err(DecoderError::RlpIncorrectListLen); } - let hash = decoder.as_raw().sha3(); + let hash = d.as_raw().sha3(); Ok(UnverifiedTransaction { unsigned: Transaction { nonce: d.val_at(0)?, diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 7fbeb29bb..ab21ef6c2 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -26,7 +26,7 @@ use engines::Engine; use error::{BlockError, Error}; use blockchain::*; use header::{BlockNumber, Header}; -use rlp::{UntrustedRlp, View}; +use rlp::UntrustedRlp; use transaction::SignedTransaction; use views::BlockView; use time::get_time; @@ -101,7 +101,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: & verify_parent(&header, &parent)?; engine.verify_block_family(&header, &parent, Some(bytes))?; - let num_uncles = UntrustedRlp::new(bytes).at(2)?.item_count(); + let num_uncles = UntrustedRlp::new(bytes).at(2)?.item_count()?; if num_uncles != 0 { if num_uncles > engine.maximum_uncle_count() { return Err(From::from(BlockError::TooManyUncles(OutOfBounds { min: None, max: Some(engine.maximum_uncle_count()), found: num_uncles }))); @@ -264,7 +264,6 @@ mod tests { use transaction::*; use tests::helpers::*; use types::log_entry::{LogEntry, LocalizedLogEntry}; - use rlp::View; use time::get_time; use encoded; diff --git a/ethcore/src/views/block.rs b/ethcore/src/views/block.rs index a03151d40..463eb7240 100644 --- a/ethcore/src/views/block.rs +++ b/ethcore/src/views/block.rs @@ -20,7 +20,7 @@ use util::*; use header::*; use transaction::*; use super::{TransactionView, HeaderView}; -use rlp::{Rlp, View}; +use rlp::Rlp; /// View onto block rlp. pub struct BlockView<'a> { @@ -69,7 +69,7 @@ impl<'a> BlockView<'a> { /// Return List of transactions in given block. pub fn transactions(&self) -> Vec { - self.rlp.val_at(1) + self.rlp.list_at(1) } /// Return List of transactions with additional localization info. @@ -125,7 +125,7 @@ impl<'a> BlockView<'a> { /// Return list of uncles of given block. pub fn uncles(&self) -> Vec
{ - self.rlp.val_at(2) + self.rlp.list_at(2) } /// Return number of uncles in given block, without deserializing them. diff --git a/ethcore/src/views/body.rs b/ethcore/src/views/body.rs index f3ae0da37..c32796628 100644 --- a/ethcore/src/views/body.rs +++ b/ethcore/src/views/body.rs @@ -20,7 +20,7 @@ use util::*; use header::*; use transaction::*; use super::{TransactionView, HeaderView}; -use rlp::{Rlp, View}; +use rlp::Rlp; /// View onto block rlp. pub struct BodyView<'a> { @@ -49,7 +49,7 @@ impl<'a> BodyView<'a> { /// Return List of transactions in given block. pub fn transactions(&self) -> Vec { - self.rlp.val_at(0) + self.rlp.list_at(0) } /// Return List of transactions with additional localization info. @@ -99,7 +99,7 @@ impl<'a> BodyView<'a> { /// Return list of uncles of given block. pub fn uncles(&self) -> Vec
{ - self.rlp.val_at(1) + self.rlp.list_at(1) } /// Return number of uncles in given block, without deserializing them. diff --git a/ethcore/src/views/header.rs b/ethcore/src/views/header.rs index 9fa07ccc8..618728525 100644 --- a/ethcore/src/views/header.rs +++ b/ethcore/src/views/header.rs @@ -17,7 +17,7 @@ //! View onto block header rlp use util::{U256, Bytes, Hashable, H256, Address, H2048}; -use rlp::{Rlp, View}; +use rlp::Rlp; use header::BlockNumber; /// View onto block header rlp. diff --git a/ethcore/src/views/transaction.rs b/ethcore/src/views/transaction.rs index 72f4e808d..0b5b2e1ff 100644 --- a/ethcore/src/views/transaction.rs +++ b/ethcore/src/views/transaction.rs @@ -16,7 +16,7 @@ //! View onto transaction rlp use util::{U256, Bytes, Hashable, H256}; -use rlp::{Rlp, View}; +use rlp::Rlp; /// View onto transaction rlp. pub struct TransactionView<'a> { diff --git a/local-store/src/lib.rs b/local-store/src/lib.rs index f9e5fe385..d21ca031d 100644 --- a/local-store/src/lib.rs +++ b/local-store/src/lib.rs @@ -25,7 +25,7 @@ use ethcore::transaction::{ }; use ethcore::service::ClientIoMessage; use io::IoHandler; -use rlp::{UntrustedRlp, View}; +use rlp::UntrustedRlp; use util::kvdb::KeyValueDB; extern crate ethcore; diff --git a/parity/informant.rs b/parity/informant.rs index 2fa95db9a..4145b0282 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -32,7 +32,6 @@ use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; use number_prefix::{binary_prefix, Standalone, Prefixed}; use ethcore_rpc::{is_major_importing}; use ethcore_rpc::informant::RpcStats; -use rlp::View; pub struct Informant { report: RwLock>, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 52bc2de71..811d5aa90 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -21,7 +21,7 @@ use std::time::{Instant, Duration}; use std::sync::{Arc, Weak}; use futures::{self, future, BoxFuture, Future}; -use rlp::{self, UntrustedRlp, View}; +use rlp::{self, UntrustedRlp}; use time::get_time; use util::{H160, H256, Address, U256, H64}; use util::sha3::Hashable; diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 1c3d8fffd..c6f0d709d 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -36,7 +36,7 @@ use ethcore::executed::{Executed, ExecutionError}; use ethcore::ids::BlockId; use ethcore::transaction::{Action, SignedTransaction, Transaction as EthTransaction}; use ethsync::LightSync; -use rlp::{UntrustedRlp, View}; +use rlp::UntrustedRlp; use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY_LIST_RLP}; use util::{RwLock, Mutex, Uint, U256}; diff --git a/rpc/src/v1/impls/signer.rs b/rpc/src/v1/impls/signer.rs index ffd9f4108..f418a6760 100644 --- a/rpc/src/v1/impls/signer.rs +++ b/rpc/src/v1/impls/signer.rs @@ -18,7 +18,7 @@ use std::sync::{Arc, Weak}; -use rlp::{UntrustedRlp, View}; +use rlp::UntrustedRlp; use ethcore::account_provider::AccountProvider; use ethcore::transaction::{SignedTransaction, PendingTransaction}; use futures::{future, BoxFuture, Future, IntoFuture}; diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index b4be40a56..466dbb88c 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -18,7 +18,7 @@ use std::sync::{Weak, Arc}; -use rlp::{UntrustedRlp, View}; +use rlp::UntrustedRlp; use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId}; use ethcore::miner::MinerService; use ethcore::transaction::SignedTransaction; diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index ee27c27ba..dfd64d38d 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -940,7 +940,7 @@ fn rpc_eth_send_raw_transaction_error() { ], "id": 1 }"#; - let res = r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid RLP.","data":"RlpIncorrectListLen"},"id":1}"#.into(); + let res = r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid RLP.","data":"RlpExpectedToBeList"},"id":1}"#.into(); assert_eq!(tester.io.handle_request_sync(&req), Some(res)); } diff --git a/sync/src/block_sync.rs b/sync/src/block_sync.rs index 50df6a0c0..e7192d525 100644 --- a/sync/src/block_sync.rs +++ b/sync/src/block_sync.rs @@ -214,7 +214,7 @@ impl BlockDownloader { /// Add new block headers. pub fn import_headers(&mut self, io: &mut SyncIo, r: &UntrustedRlp, expected_hash: Option) -> Result { - let item_count = r.item_count(); + let item_count = r.item_count().unwrap_or(0); if self.state == State::Idle { trace!(target: "sync", "Ignored unexpected block headers"); return Ok(DownloadAction::None) @@ -314,7 +314,7 @@ impl BlockDownloader { /// Called by peer once it has new block bodies pub fn import_bodies(&mut self, _io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), BlockDownloaderImportError> { - let item_count = r.item_count(); + let item_count = r.item_count().unwrap_or(0); if item_count == 0 { return Err(BlockDownloaderImportError::Useless); } @@ -340,7 +340,7 @@ impl BlockDownloader { /// Called by peer once it has new block bodies pub fn import_receipts(&mut self, _io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), BlockDownloaderImportError> { - let item_count = r.item_count(); + let item_count = r.item_count().unwrap_or(0); if item_count == 0 { return Err(BlockDownloaderImportError::Useless); } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 415b44a39..47ddf6ab1 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -659,7 +659,7 @@ impl ChainSync { let confirmed = match self.peers.get_mut(&peer_id) { Some(ref mut peer) if peer.asking == PeerAsking::ForkHeader => { peer.asking = PeerAsking::Nothing; - let item_count = r.item_count(); + let item_count = r.item_count()?; let (fork_number, fork_hash) = self.fork_block.expect("ForkHeader request is sent only fork block is Some; qed").clone(); if item_count == 0 || item_count != 1 { trace!(target: "sync", "{}: Chain is too short to confirm the block", peer_id); @@ -696,7 +696,7 @@ impl ChainSync { self.continue_sync(io); return Ok(()); } - let item_count = r.item_count(); + let item_count = r.item_count()?; trace!(target: "sync", "{} -> BlockHeaders ({} entries), state = {:?}, set = {:?}", peer_id, item_count, self.state, block_set); if (self.state == SyncState::Idle || self.state == SyncState::WaitingPeers) && self.old_blocks.is_none() { trace!(target: "sync", "Ignored unexpected block headers"); @@ -764,7 +764,7 @@ impl ChainSync { self.continue_sync(io); return Ok(()); } - let item_count = r.item_count(); + let item_count = r.item_count()?; trace!(target: "sync", "{} -> BlockBodies ({} entries), set = {:?}", peer_id, item_count, block_set); if item_count == 0 { self.deactivate_peer(io, peer_id); @@ -818,7 +818,7 @@ impl ChainSync { self.continue_sync(io); return Ok(()); } - let item_count = r.item_count(); + let item_count = r.item_count()?; trace!(target: "sync", "{} -> BlockReceipts ({} entries)", peer_id, item_count); if item_count == 0 { self.deactivate_peer(io, peer_id); @@ -954,7 +954,7 @@ impl ChainSync { self.continue_sync(io); return Ok(()); } - trace!(target: "sync", "{} -> NewHashes ({} entries)", peer_id, r.item_count()); + trace!(target: "sync", "{} -> NewHashes ({} entries)", peer_id, r.item_count()?); let mut max_height: BlockNumber = 0; let mut new_hashes = Vec::new(); let last_imported_number = self.new_blocks.last_imported_block_number(); @@ -1439,7 +1439,7 @@ impl ChainSync { trace!(target: "sync", "{} Ignoring transactions from unconfirmed/unknown peer", peer_id); } - let mut item_count = r.item_count(); + let mut item_count = r.item_count()?; trace!(target: "sync", "{:02} -> Transactions ({} entries)", peer_id, item_count); item_count = min(item_count, MAX_TX_TO_IMPORT); let mut transactions = Vec::with_capacity(item_count); @@ -1557,7 +1557,7 @@ impl ChainSync { /// Respond to GetBlockBodies request fn return_block_bodies(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { - let mut count = r.item_count(); + let mut count = r.item_count().unwrap_or(0); if count == 0 { debug!(target: "sync", "Empty GetBlockBodies request, ignoring."); return Ok(None); @@ -1579,7 +1579,7 @@ impl ChainSync { /// Respond to GetNodeData request fn return_node_data(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { - let mut count = r.item_count(); + let mut count = r.item_count().unwrap_or(0); trace!(target: "sync", "{} -> GetNodeData: {} entries", peer_id, count); if count == 0 { debug!(target: "sync", "Empty GetNodeData request, ignoring."); @@ -1603,7 +1603,7 @@ impl ChainSync { } fn return_receipts(io: &SyncIo, rlp: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { - let mut count = rlp.item_count(); + let mut count = rlp.item_count().unwrap_or(0); trace!(target: "sync", "{} -> GetReceipts: {} entries", peer_id, count); if count == 0 { debug!(target: "sync", "Empty GetReceipts request, ignoring."); @@ -1628,7 +1628,7 @@ impl ChainSync { /// Respond to GetSnapshotManifest request fn return_snapshot_manifest(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { - let count = r.item_count(); + let count = r.item_count().unwrap_or(0); trace!(target: "sync", "{} -> GetSnapshotManifest", peer_id); if count != 0 { debug!(target: "sync", "Invalid GetSnapshotManifest request, ignoring."); @@ -2177,7 +2177,7 @@ mod tests { use util::sha3::Hashable; use util::hash::H256; use util::bytes::Bytes; - use rlp::{Rlp, RlpStream, UntrustedRlp, View}; + use rlp::{Rlp, RlpStream, UntrustedRlp}; use super::*; use ::SyncConfig; use super::{PeerInfo, PeerAsking}; @@ -2746,7 +2746,7 @@ mod tests { } let rlp = UntrustedRlp::new(&*p.data); - let item_count = rlp.item_count(); + let item_count = rlp.item_count().unwrap_or(0); if item_count != 1 { return None; } diff --git a/sync/src/light_sync/response.rs b/sync/src/light_sync/response.rs index cb95824ce..0629da956 100644 --- a/sync/src/light_sync/response.rs +++ b/sync/src/light_sync/response.rs @@ -20,7 +20,7 @@ use std::fmt; use ethcore::header::Header; use light::request::{HashOrNumber, Headers as HeadersRequest}; -use rlp::{DecoderError, UntrustedRlp, View}; +use rlp::{DecoderError, UntrustedRlp}; use util::{Bytes, H256}; /// Errors found when decoding headers and verifying with basic constraints. diff --git a/util/network/src/discovery.rs b/util/network/src/discovery.rs index ae4c7e565..ad995188d 100644 --- a/util/network/src/discovery.rs +++ b/util/network/src/discovery.rs @@ -481,7 +481,7 @@ impl Discovery { fn on_neighbours(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { // TODO: validate packet let mut added = HashMap::new(); - trace!(target: "discovery", "Got {} Neighbours from {:?}", rlp.at(0)?.item_count(), &from); + trace!(target: "discovery", "Got {} Neighbours from {:?}", rlp.at(0)?.item_count()?, &from); for r in rlp.at(0)?.iter() { let endpoint = NodeEndpoint::from_rlp(&r)?; if !endpoint.is_valid() { diff --git a/util/network/src/session.rs b/util/network/src/session.rs index bc416b8d8..59eac6e5d 100644 --- a/util/network/src/session.rs +++ b/util/network/src/session.rs @@ -116,9 +116,8 @@ pub struct PeerCapabilityInfo { } impl Decodable for PeerCapabilityInfo { - fn decode(decoder: &D) -> Result where D: Decoder { - let c = decoder.as_rlp(); - let p: Vec = c.val_at(0)?; + fn decode(rlp: &UntrustedRlp) -> Result { + let p: Vec = rlp.val_at(0)?; if p.len() != 3 { return Err(DecoderError::Custom("Invalid subprotocol string length. Should be 3")); } @@ -126,7 +125,7 @@ impl Decodable for PeerCapabilityInfo { p2.clone_from_slice(&p); Ok(PeerCapabilityInfo { protocol: p2, - version: c.val_at(1)? + version: rlp.val_at(1)? }) } } @@ -473,7 +472,7 @@ impl Session { where Message: Send + Sync + Clone { let protocol = rlp.val_at::(0)?; let client_version = rlp.val_at::(1)?; - let peer_caps = rlp.val_at::>(2)?; + let peer_caps: Vec = rlp.list_at(2)?; let id = rlp.val_at::(4)?; // Intersect with host capabilities diff --git a/util/benches/rlp.rs b/util/rlp/benches/rlp.rs similarity index 85% rename from util/benches/rlp.rs rename to util/rlp/benches/rlp.rs index d5aac0d22..3f8166ec4 100644 --- a/util/benches/rlp.rs +++ b/util/rlp/benches/rlp.rs @@ -23,13 +23,12 @@ #![feature(test)] extern crate test; +extern crate ethcore_bigint as bigint; extern crate rlp; -extern crate ethcore_util as util; use test::Bencher; -use std::str::FromStr; -use rlp::*; -use util::U256; +use bigint::prelude::U256; +use rlp::{RlpStream, Rlp}; #[bench] fn bench_stream_u64_value(b: &mut Bencher) { @@ -56,9 +55,8 @@ fn bench_stream_u256_value(b: &mut Bencher) { b.iter(|| { // u256 let mut stream = RlpStream::new(); - stream.append(&U256::from_str("8090a0b0c0d0e0f009102030405060770000000000000001000000000\ - 00012f0") - .unwrap()); + let uint: U256 = "8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0".into(); + stream.append(&uint); let _ = stream.out(); }); } @@ -93,11 +91,11 @@ fn bench_decode_nested_empty_lists(b: &mut Bencher) { // [ [], [[]], [ [], [[]] ] ] let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]; let rlp = Rlp::new(&data); - let _v0: Vec = rlp.val_at(0); - let _v1: Vec> = rlp.val_at(1); + let _v0: Vec = rlp.at(0).as_list(); + let _v1: Vec = rlp.at(1).at(0).as_list(); let nested_rlp = rlp.at(2); - let _v2a: Vec = nested_rlp.val_at(0); - let _v2b: Vec> = nested_rlp.val_at(1); + let _v2a: Vec = nested_rlp.at(0).as_list(); + let _v2b: Vec = nested_rlp.at(1).at(0).as_list(); }); } diff --git a/util/rlp/src/bytes.rs b/util/rlp/src/bytes.rs deleted file mode 100644 index e5f266f92..000000000 --- a/util/rlp/src/bytes.rs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity 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 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. If not, see . - -//! Unified interfaces for RLP bytes operations on basic types -//! - -use std::{mem, fmt, cmp}; -use std::error::Error as StdError; -use bigint::prelude::{U128, U256, H64, H128, H160, H256, H512, H520, H2048}; - -/// Error returned when `FromBytes` conversation goes wrong -#[derive(Debug, PartialEq, Eq)] -pub enum FromBytesError { - /// Expected more RLP data - DataIsTooShort, - /// Extra bytes after the end of the last item - DataIsTooLong, - /// Integer-representation is non-canonically prefixed with zero byte(s). - ZeroPrefixedInt, - /// String representation is not utf-8 - InvalidUtf8, -} - -impl StdError for FromBytesError { - fn description(&self) -> &str { "from_bytes error" } -} - -impl fmt::Display for FromBytesError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self, f) - } -} - -/// Alias for the result of `FromBytes` trait -pub type FromBytesResult = Result; - -/// Converts to given type from its bytes representation -/// -/// TODO: check size of bytes before conversation and return appropriate error -pub trait FromBytes: Sized { - /// Create a value from bytes - fn from_bytes(bytes: &[u8]) -> FromBytesResult; -} - -impl FromBytes for String { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - ::std::str::from_utf8(bytes).map(|s| s.to_owned()).map_err(|_| FromBytesError::InvalidUtf8) - } -} - -macro_rules! impl_uint_from_bytes { - ($to: ident) => { - impl FromBytes for $to { - fn from_bytes(bytes: &[u8]) -> FromBytesResult<$to> { - match bytes.len() { - 0 => Ok(0), - l if l <= mem::size_of::<$to>() => { - if bytes[0] == 0 { - return Err(FromBytesError::ZeroPrefixedInt) - } - let mut res = 0 as $to; - for i in 0..l { - let shift = (l - 1 - i) * 8; - res = res + ((bytes[i] as $to) << shift); - } - Ok(res) - } - _ => Err(FromBytesError::DataIsTooLong) - } - } - } - } -} - -impl FromBytes for bool { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - match bytes.len() { - 0 => Ok(false), - 1 => Ok(bytes[0] != 0), - _ => Err(FromBytesError::DataIsTooLong), - } - } -} - -//impl_uint_from_bytes!(u8); -impl_uint_from_bytes!(u16); -impl_uint_from_bytes!(u32); -impl_uint_from_bytes!(u64); -impl_uint_from_bytes!(usize); - -macro_rules! impl_uint_from_bytes { - ($name: ident, $size: expr) => { - impl FromBytes for $name { - fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { - if !bytes.is_empty() && bytes[0] == 0 { - Err(FromBytesError::ZeroPrefixedInt) - } else if bytes.len() <= $size { - Ok($name::from(bytes)) - } else { - Err(FromBytesError::DataIsTooLong) - } - } - } - } -} - -impl_uint_from_bytes!(U256, 32); -impl_uint_from_bytes!(U128, 16); - -macro_rules! impl_hash_from_bytes { - ($name: ident, $size: expr) => { - impl FromBytes for $name { - fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { - match bytes.len().cmp(&$size) { - cmp::Ordering::Less => Err(FromBytesError::DataIsTooShort), - cmp::Ordering::Greater => Err(FromBytesError::DataIsTooLong), - cmp::Ordering::Equal => { - let mut t = [0u8; $size]; - t.copy_from_slice(bytes); - Ok($name(t)) - } - } - } - } - } -} - -impl_hash_from_bytes!(H64, 8); -impl_hash_from_bytes!(H128, 16); -impl_hash_from_bytes!(H160, 20); -impl_hash_from_bytes!(H256, 32); -impl_hash_from_bytes!(H512, 64); -impl_hash_from_bytes!(H520, 65); -impl_hash_from_bytes!(H2048, 256); - diff --git a/util/rlp/src/compression.rs b/util/rlp/src/compression.rs index b7cf72a4f..7a9c5a917 100644 --- a/util/rlp/src/compression.rs +++ b/util/rlp/src/compression.rs @@ -17,7 +17,7 @@ use std::collections::HashMap; use elastic_array::ElasticArray1024; use common::{BLOCKS_RLP_SWAPPER, SNAPSHOT_RLP_SWAPPER}; -use {UntrustedRlp, View, Compressible, encode, RlpStream}; +use {UntrustedRlp, Compressible, encode, RlpStream}; /// Stores RLPs used for compression pub struct InvalidRlpSwapper<'a> { @@ -69,7 +69,7 @@ fn to_elastic(slice: &[u8]) -> ElasticArray1024 { fn map_rlp(rlp: &UntrustedRlp, f: F) -> Option> where F: Fn(&UntrustedRlp) -> Option> { match rlp.iter() - .fold((false, RlpStream::new_list(rlp.item_count())), + .fold((false, RlpStream::new_list(rlp.item_count().unwrap_or(0))), |(is_some, mut acc), subrlp| { let new = f(&subrlp); if let Some(ref insert) = new { @@ -138,7 +138,7 @@ fn deep_decompress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option rlp.at(1).ok().map_or(simple_swap(), @@ -169,7 +169,7 @@ impl<'a> Compressible for UntrustedRlp<'a> { #[cfg(test)] mod tests { use compression::InvalidRlpSwapper; - use {UntrustedRlp, Compressible, View, RlpType}; + use {UntrustedRlp, Compressible, RlpType}; #[test] fn invalid_rlp_swapper() { diff --git a/util/rlp/src/error.rs b/util/rlp/src/error.rs index f3b43f850..4ad754dd0 100644 --- a/util/rlp/src/error.rs +++ b/util/rlp/src/error.rs @@ -16,13 +16,10 @@ use std::fmt; use std::error::Error as StdError; -use bytes::FromBytesError; #[derive(Debug, PartialEq, Eq)] /// Error concerning the RLP decoder. pub enum DecoderError { - /// Couldn't convert given bytes to an instance of required type. - FromBytesError(FromBytesError), /// Data has additional bytes at the end of the valid RLP fragment. RlpIsTooBig, /// Data has too few bytes for valid RLP. @@ -56,9 +53,3 @@ impl fmt::Display for DecoderError { fmt::Debug::fmt(&self, f) } } - -impl From for DecoderError { - fn from(err: FromBytesError) -> DecoderError { - DecoderError::FromBytesError(err) - } -} diff --git a/util/rlp/src/impls.rs b/util/rlp/src/impls.rs index affac1ddc..909f3bd63 100644 --- a/util/rlp/src/impls.rs +++ b/util/rlp/src/impls.rs @@ -1,7 +1,26 @@ +use std::{cmp, mem, str}; use byteorder::{ByteOrder, BigEndian}; use bigint::prelude::{Uint, U128, U256, H64, H128, H160, H256, H512, H520, H2048}; -use traits::Encodable; +use traits::{Encodable, Decodable}; use stream::RlpStream; +use {UntrustedRlp, DecoderError}; + +pub fn decode_usize(bytes: &[u8]) -> Result { + match bytes.len() { + l if l <= mem::size_of::() => { + if bytes[0] == 0 { + return Err(DecoderError::RlpInvalidIndirection); + } + let mut res = 0usize; + for i in 0..l { + let shift = (l - 1 - i) * 8; + res = res + ((bytes[i] as usize) << shift); + } + Ok(res) + } + _ => Err(DecoderError::RlpIsTooBig), + } +} impl Encodable for bool { fn rlp_append(&self, s: &mut RlpStream) { @@ -13,6 +32,18 @@ impl Encodable for bool { } } +impl Decodable for bool { + fn decode(rlp: &UntrustedRlp) -> Result { + rlp.decoder().decode_value(|bytes| { + match bytes.len() { + 0 => Ok(false), + 1 => Ok(bytes[0] != 0), + _ => Err(DecoderError::RlpIsTooBig), + } + }) + } +} + impl<'a> Encodable for &'a [u8] { fn rlp_append(&self, s: &mut RlpStream) { s.encoder().encode_value(self); @@ -25,6 +56,14 @@ impl Encodable for Vec { } } +impl Decodable for Vec { + fn decode(rlp: &UntrustedRlp) -> Result { + rlp.decoder().decode_value(|bytes| { + Ok(bytes.to_vec()) + }) + } +} + impl Encodable for Option where T: Encodable { fn rlp_append(&self, s: &mut RlpStream) { match *self { @@ -39,6 +78,17 @@ impl Encodable for Option where T: Encodable { } } +impl Decodable for Option where T: Decodable { + fn decode(rlp: &UntrustedRlp) -> Result { + let items = rlp.item_count()?; + match items { + 1 => rlp.val_at(0).map(Some), + 0 => Ok(None), + _ => Err(DecoderError::RlpIncorrectListLen), + } + } +} + impl Encodable for u8 { fn rlp_append(&self, s: &mut RlpStream) { if *self != 0 { @@ -49,6 +99,19 @@ impl Encodable for u8 { } } +impl Decodable for u8 { + fn decode(rlp: &UntrustedRlp) -> Result { + rlp.decoder().decode_value(|bytes| { + match bytes.len() { + 1 if bytes[0] != 0 => Ok(bytes[0]), + 0 => Ok(0), + 1 => Err(DecoderError::RlpInvalidIndirection), + _ => Err(DecoderError::RlpIsTooBig), + } + }) + } +} + macro_rules! impl_encodable_for_u { ($name: ident, $func: ident, $size: expr) => { impl Encodable for $name { @@ -62,16 +125,52 @@ macro_rules! impl_encodable_for_u { } } +macro_rules! impl_decodable_for_u { + ($name: ident) => { + impl Decodable for $name { + fn decode(rlp: &UntrustedRlp) -> Result { + rlp.decoder().decode_value(|bytes| { + match bytes.len() { + 0 | 1 => u8::decode(rlp).map(|v| v as $name), + l if l <= mem::size_of::<$name>() => { + if bytes[0] == 0 { + return Err(DecoderError::RlpInvalidIndirection); + } + let mut res = 0 as $name; + for i in 0..l { + let shift = (l - 1 - i) * 8; + res = res + ((bytes[i] as $name) << shift); + } + Ok(res) + } + _ => Err(DecoderError::RlpIsTooBig), + } + }) + } + } + } +} + impl_encodable_for_u!(u16, write_u16, 2); impl_encodable_for_u!(u32, write_u32, 4); impl_encodable_for_u!(u64, write_u64, 8); +impl_decodable_for_u!(u16); +impl_decodable_for_u!(u32); +impl_decodable_for_u!(u64); + impl Encodable for usize { fn rlp_append(&self, s: &mut RlpStream) { (*self as u64).rlp_append(s); } } +impl Decodable for usize { + fn decode(rlp: &UntrustedRlp) -> Result { + u64::decode(rlp).map(|value| value as usize) + } +} + macro_rules! impl_encodable_for_hash { ($name: ident) => { impl Encodable for $name { @@ -82,6 +181,24 @@ macro_rules! impl_encodable_for_hash { } } +macro_rules! impl_decodable_for_hash { + ($name: ident, $size: expr) => { + impl Decodable for $name { + fn decode(rlp: &UntrustedRlp) -> Result { + rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&$size) { + cmp::Ordering::Less => Err(DecoderError::RlpIsTooShort), + cmp::Ordering::Greater => Err(DecoderError::RlpIsTooBig), + cmp::Ordering::Equal => { + let mut t = [0u8; $size]; + t.copy_from_slice(bytes); + Ok($name(t)) + } + }) + } + } + } +} + impl_encodable_for_hash!(H64); impl_encodable_for_hash!(H128); impl_encodable_for_hash!(H160); @@ -90,6 +207,14 @@ impl_encodable_for_hash!(H512); impl_encodable_for_hash!(H520); impl_encodable_for_hash!(H2048); +impl_decodable_for_hash!(H64, 8); +impl_decodable_for_hash!(H128, 16); +impl_decodable_for_hash!(H160, 20); +impl_decodable_for_hash!(H256, 32); +impl_decodable_for_hash!(H512, 64); +impl_decodable_for_hash!(H520, 65); +impl_decodable_for_hash!(H2048, 256); + macro_rules! impl_encodable_for_uint { ($name: ident, $size: expr) => { impl Encodable for $name { @@ -103,9 +228,30 @@ macro_rules! impl_encodable_for_uint { } } +macro_rules! impl_decodable_for_uint { + ($name: ident, $size: expr) => { + impl Decodable for $name { + fn decode(rlp: &UntrustedRlp) -> Result { + rlp.decoder().decode_value(|bytes| { + if !bytes.is_empty() && bytes[0] == 0 { + Err(DecoderError::RlpInvalidIndirection) + } else if bytes.len() <= $size { + Ok($name::from(bytes)) + } else { + Err(DecoderError::RlpIsTooBig) + } + }) + } + } + } +} + impl_encodable_for_uint!(U256, 32); impl_encodable_for_uint!(U128, 16); +impl_decodable_for_uint!(U256, 32); +impl_decodable_for_uint!(U128, 16); + impl<'a> Encodable for &'a str { fn rlp_append(&self, s: &mut RlpStream) { s.encoder().encode_value(self.as_bytes()); @@ -118,3 +264,14 @@ impl Encodable for String { } } +impl Decodable for String { + fn decode(rlp: &UntrustedRlp) -> Result { + rlp.decoder().decode_value(|bytes| { + match str::from_utf8(bytes) { + Ok(s) => Ok(s.to_owned()), + // consider better error type here + Err(_err) => Err(DecoderError::RlpExpectedToBeData), + } + }) + } +} diff --git a/util/rlp/src/lib.rs b/util/rlp/src/lib.rs index 406501b1e..4b01691e3 100644 --- a/util/rlp/src/lib.rs +++ b/util/rlp/src/lib.rs @@ -61,17 +61,13 @@ mod untrusted_rlp; mod stream; mod compression; mod common; -mod bytes; mod impls; -#[cfg(test)] -mod tests; - use std::borrow::Borrow; use elastic_array::ElasticArray1024; pub use error::DecoderError; -pub use traits::{Decoder, Decodable, View, Encodable, RlpDecodable, Compressible}; +pub use traits::{Decodable, Encodable, Compressible}; pub use untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype}; pub use rlpin::{Rlp, RlpIterator}; pub use stream::RlpStream; @@ -88,16 +84,21 @@ pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1]; /// extern crate rlp; /// /// fn main () { -/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; -/// let animals: Vec = rlp::decode(&data); -/// assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]); +/// let data = vec![0x83, b'c', b'a', b't']; +/// let animal: String = rlp::decode(&data); +/// assert_eq!(animal, "cat".to_owned()); /// } /// ``` -pub fn decode(bytes: &[u8]) -> T where T: RlpDecodable { +pub fn decode(bytes: &[u8]) -> T where T: Decodable { let rlp = Rlp::new(bytes); rlp.as_val() } +pub fn decode_list(bytes: &[u8]) -> Vec where T: Decodable { + let rlp = Rlp::new(bytes); + rlp.as_list() +} + /// Shortcut function to encode structure into rlp. /// /// ```rust diff --git a/util/rlp/src/rlpin.rs b/util/rlp/src/rlpin.rs index 7ae715649..c7c054aa2 100644 --- a/util/rlp/src/rlpin.rs +++ b/util/rlp/src/rlpin.rs @@ -15,8 +15,7 @@ // along with Parity. If not, see . use std::fmt; -use rustc_serialize::hex::ToHex; -use {View, DecoderError, UntrustedRlp, PayloadInfo, Prototype, RlpDecodable}; +use {UntrustedRlp, PayloadInfo, Prototype, Decodable}; impl<'a> From> for Rlp<'a> { fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> { @@ -39,95 +38,215 @@ impl<'a> fmt::Display for Rlp<'a> { } } -impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view { - type Prototype = Prototype; - type PayloadInfo = PayloadInfo; - type Data = &'a [u8]; - type Item = Rlp<'a>; - type Iter = RlpIterator<'a, 'view>; - +impl<'a, 'view> Rlp<'a> where 'a: 'view { /// Create a new instance of `Rlp` - fn new(bytes: &'a [u8]) -> Rlp<'a> { + pub fn new(bytes: &'a [u8]) -> Rlp<'a> { Rlp { rlp: UntrustedRlp::new(bytes) } } - fn as_raw(&'view self) -> &'a [u8] { + /// The raw data of the RLP as slice. + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; + /// let rlp = Rlp::new(&data); + /// let dog = rlp.at(1).as_raw(); + /// assert_eq!(dog, &[0x83, b'd', b'o', b'g']); + /// } + /// ``` + pub fn as_raw(&'view self) -> &'a [u8] { self.rlp.as_raw() } - fn prototype(&self) -> Self::Prototype { + /// Get the prototype of the RLP. + pub fn prototype(&self) -> Prototype { self.rlp.prototype().unwrap() } - fn payload_info(&self) -> Self::PayloadInfo { + /// Get payload info. + pub fn payload_info(&self) -> PayloadInfo { self.rlp.payload_info().unwrap() } - fn data(&'view self) -> Self::Data { + /// Get underlieing data. + pub fn data(&'view self) -> &'a [u8] { self.rlp.data().unwrap() } - fn item_count(&self) -> usize { - self.rlp.item_count() + /// Returns number of RLP items. + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; + /// let rlp = Rlp::new(&data); + /// assert_eq!(rlp.item_count(), 2); + /// let view = rlp.at(1); + /// assert_eq!(view.item_count(), 0); + /// } + /// ``` + pub fn item_count(&self) -> usize { + self.rlp.item_count().unwrap_or(0) } - fn size(&self) -> usize { + /// Returns the number of bytes in the data, or zero if it isn't data. + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; + /// let rlp = Rlp::new(&data); + /// assert_eq!(rlp.size(), 0); + /// let view = rlp.at(1); + /// assert_eq!(view.size(), 3); + /// } + /// ``` + pub fn size(&self) -> usize { self.rlp.size() } - fn at(&'view self, index: usize) -> Self::Item { + /// Get view onto RLP-slice at index. + /// + /// Caches offset to given index, so access to successive + /// slices is faster. + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; + /// let rlp = Rlp::new(&data); + /// let dog: String = rlp.at(1).as_val(); + /// assert_eq!(dog, "dog".to_string()); + /// } + /// ``` + pub fn at(&'view self, index: usize) -> Rlp<'a> { From::from(self.rlp.at(index).unwrap()) } - fn is_null(&self) -> bool { + /// No value + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![]; + /// let rlp = Rlp::new(&data); + /// assert!(rlp.is_null()); + /// } + /// ``` + pub fn is_null(&self) -> bool { self.rlp.is_null() } - fn is_empty(&self) -> bool { + /// Contains a zero-length string or zero-length list. + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![0xc0]; + /// let rlp = Rlp::new(&data); + /// assert!(rlp.is_empty()); + /// } + /// ``` + pub fn is_empty(&self) -> bool { self.rlp.is_empty() } - fn is_list(&self) -> bool { + /// List value + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; + /// let rlp = Rlp::new(&data); + /// assert!(rlp.is_list()); + /// } + /// ``` + pub fn is_list(&self) -> bool { self.rlp.is_list() } - fn is_data(&self) -> bool { + /// String value + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; + /// let rlp = Rlp::new(&data); + /// assert!(rlp.at(1).is_data()); + /// } + /// ``` + pub fn is_data(&self) -> bool { self.rlp.is_data() } - fn is_int(&self) -> bool { + /// Int value + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![0xc1, 0x10]; + /// let rlp = Rlp::new(&data); + /// assert_eq!(rlp.is_int(), false); + /// assert_eq!(rlp.at(0).is_int(), true); + /// } + /// ``` + pub fn is_int(&self) -> bool { self.rlp.is_int() } - fn iter(&'view self) -> Self::Iter { + /// Get iterator over rlp-slices + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; + /// let rlp = Rlp::new(&data); + /// let strings: Vec = rlp.iter().map(| i | i.as_val()).collect(); + /// } + /// ``` + pub fn iter(&'view self) -> RlpIterator<'a, 'view> { self.into_iter() } - fn as_val(&self) -> Result where T: RlpDecodable { - self.rlp.as_val() + /// Decode data into an object + pub fn as_val(&self) -> T where T: Decodable { + self.rlp.as_val().expect("Unexpected rlp error") } - fn val_at(&self, index: usize) -> Result where T: RlpDecodable { - self.at(index).rlp.as_val() - } -} - -impl <'a, 'view> Rlp<'a> where 'a: 'view { - fn view_as_val(r: &'view R) -> T where R: View<'a, 'view>, T: RlpDecodable { - let res: Result = r.as_val(); - res.unwrap_or_else(|e| panic!("DecodeError: {}, {}", e, r.as_raw().to_hex())) + pub fn as_list(&self) -> Vec where T: Decodable { + self.iter().map(|rlp| rlp.as_val()).collect() } - /// Decode into an object - pub fn as_val(&self) -> T where T: RlpDecodable { - Self::view_as_val(self) + /// Decode data at given list index into an object + pub fn val_at(&self, index: usize) -> T where T: Decodable { + self.at(index).as_val() } - /// Decode list item at given index into an object - pub fn val_at(&self, index: usize) -> T where T: RlpDecodable { - Self::view_as_val(&self.at(index)) + pub fn list_at(&self, index: usize) -> Vec where T: Decodable { + self.at(index).as_list() } } diff --git a/util/rlp/src/traits.rs b/util/rlp/src/traits.rs index 3f79e9cab..33c5ae548 100644 --- a/util/rlp/src/traits.rs +++ b/util/rlp/src/traits.rs @@ -16,212 +16,12 @@ //! Common RLP traits use elastic_array::ElasticArray1024; -use stream::RlpStream; -use {DecoderError, UntrustedRlp}; - -/// Type is able to decode RLP. -pub trait Decoder: Sized { - /// Read a value from the RLP into a given type. - fn read_value(&self, f: &F) -> Result - where F: Fn(&[u8]) -> Result; - - /// Get underlying `UntrustedRLP` object. - fn as_rlp(&self) -> &UntrustedRlp; - /// Get underlying raw bytes slice. - fn as_raw(&self) -> &[u8]; -} +use {DecoderError, UntrustedRlp, RlpStream}; /// RLP decodable trait pub trait Decodable: Sized { /// Decode a value from RLP bytes - fn decode(decoder: &D) -> Result where D: Decoder; -} - -/// Internal helper trait. Implement `Decodable` for custom types. -pub trait RlpDecodable: Sized { - /// Decode a value from RLP bytes - fn decode(decoder: &D) -> Result where D: Decoder; -} - -/// A view into RLP encoded data -pub trait View<'a, 'view>: Sized { - /// RLP prototype type - type Prototype; - /// Payload info type - type PayloadInfo; - /// Data type - type Data; - /// Item type - type Item; - /// Iterator type - type Iter; - - /// Creates a new instance of `Rlp` reader - fn new(bytes: &'a [u8]) -> Self; - - /// The raw data of the RLP as slice. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let dog = rlp.at(1).as_raw(); - /// assert_eq!(dog, &[0x83, b'd', b'o', b'g']); - /// } - /// ``` - fn as_raw(&'view self) -> &'a [u8]; - - /// Get the prototype of the RLP. - fn prototype(&self) -> Self::Prototype; - - /// Get payload info. - fn payload_info(&self) -> Self::PayloadInfo; - - /// Get underlieing data. - fn data(&'view self) -> Self::Data; - - /// Returns number of RLP items. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.item_count(), 2); - /// let view = rlp.at(1); - /// assert_eq!(view.item_count(), 0); - /// } - /// ``` - fn item_count(&self) -> usize; - - /// Returns the number of bytes in the data, or zero if it isn't data. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.size(), 0); - /// let view = rlp.at(1); - /// assert_eq!(view.size(), 3); - /// } - /// ``` - fn size(&self) -> usize; - - /// Get view onto RLP-slice at index. - /// - /// Caches offset to given index, so access to successive - /// slices is faster. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let dog: String = rlp.at(1).as_val(); - /// assert_eq!(dog, "dog".to_string()); - /// } - fn at(&'view self, index: usize) -> Self::Item; - - /// No value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![]; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_null()); - /// } - /// ``` - fn is_null(&self) -> bool; - - /// Contains a zero-length string or zero-length list. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc0]; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_empty()); - /// } - /// ``` - fn is_empty(&self) -> bool; - - /// List value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_list()); - /// } - /// ``` - fn is_list(&self) -> bool; - - /// String value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.at(1).is_data()); - /// } - /// ``` - fn is_data(&self) -> bool; - - /// Int value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc1, 0x10]; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.is_int(), false); - /// assert_eq!(rlp.at(0).is_int(), true); - /// } - /// ``` - fn is_int(&self) -> bool; - - /// Get iterator over rlp-slices - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let strings: Vec = rlp.iter().map(| i | i.as_val()).collect(); - /// } - /// ``` - fn iter(&'view self) -> Self::Iter; - - /// Decode data into an object - fn as_val(&self) -> Result where T: RlpDecodable; - - /// Decode data at given list index into an object - fn val_at(&self, index: usize) -> Result where T: RlpDecodable; + fn decode(rlp: &UntrustedRlp) -> Result; } /// Structure encodable to RLP diff --git a/util/rlp/src/untrusted_rlp.rs b/util/rlp/src/untrusted_rlp.rs index e111fde18..8f46bb690 100644 --- a/util/rlp/src/untrusted_rlp.rs +++ b/util/rlp/src/untrusted_rlp.rs @@ -17,9 +17,8 @@ use std::cell::Cell; use std::fmt; use rustc_serialize::hex::ToHex; - -use bytes::{FromBytes, FromBytesResult, FromBytesError}; -use ::{View, Decoder, Decodable, DecoderError, RlpDecodable}; +use impls::decode_usize; +use {Decodable, DecoderError}; /// rlp offset #[derive(Copy, Clone, Debug)] @@ -64,7 +63,7 @@ fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result (), } if header_bytes.len() < header_len { return Err(DecoderError::RlpIsTooShort); } - let value_len = usize::from_bytes(&header_bytes[1..header_len])?; + let value_len = decode_usize(&header_bytes[1..header_len])?; Ok(PayloadInfo::new(header_len, value_len)) } @@ -141,15 +140,8 @@ impl<'a> fmt::Display for UntrustedRlp<'a> { } } -impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view { - type Prototype = Result; - type PayloadInfo = Result; - type Data = Result<&'a [u8], DecoderError>; - type Item = Result, DecoderError>; - type Iter = UntrustedRlpIterator<'a, 'view>; - - //returns new instance of `UntrustedRlp` - fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> { +impl<'a, 'view> UntrustedRlp<'a> where 'a: 'view { + pub fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> { UntrustedRlp { bytes: bytes, offset_cache: Cell::new(OffsetCache::new(usize::max_value(), 0)), @@ -157,45 +149,45 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view { } } - fn as_raw(&'view self) -> &'a [u8] { + pub fn as_raw(&'view self) -> &'a [u8] { self.bytes } - fn prototype(&self) -> Self::Prototype { + pub fn prototype(&self) -> Result { // optimize? && return appropriate errors if self.is_data() { Ok(Prototype::Data(self.size())) } else if self.is_list() { - Ok(Prototype::List(self.item_count())) + self.item_count().map(Prototype::List) } else { Ok(Prototype::Null) } } - fn payload_info(&self) -> Self::PayloadInfo { + pub fn payload_info(&self) -> Result { BasicDecoder::payload_info(self.bytes) } - fn data(&'view self) -> Self::Data { + pub fn data(&'view self) -> Result<&'a [u8], DecoderError> { let pi = BasicDecoder::payload_info(self.bytes)?; Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)]) } - fn item_count(&self) -> usize { + pub fn item_count(&self) -> Result { match self.is_list() { true => match self.count_cache.get() { - Some(c) => c, + Some(c) => Ok(c), None => { let c = self.iter().count(); self.count_cache.set(Some(c)); - c + Ok(c) } }, - false => 0 + false => Err(DecoderError::RlpExpectedToBeList), } } - fn size(&self) -> usize { + pub fn size(&self) -> usize { match self.is_data() { // TODO: No panic on malformed data, but ideally would Err on no PayloadInfo. true => BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0), @@ -203,7 +195,7 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view { } } - fn at(&'view self, index: usize) -> Self::Item { + pub fn at(&'view self, index: usize) -> Result, DecoderError> { if !self.is_list() { return Err(DecoderError::RlpExpectedToBeList); } @@ -213,7 +205,7 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view { let c = self.offset_cache.get(); let (mut bytes, to_skip) = match c.index <= index { true => (UntrustedRlp::consume(self.bytes, c.offset)?, index - c.index), - false => (self.consume_list_prefix()?, index), + false => (self.consume_list_payload()?, index), }; // skip up to x items @@ -227,23 +219,23 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view { Ok(UntrustedRlp::new(&bytes[0..found.header_len + found.value_len])) } - fn is_null(&self) -> bool { + pub fn is_null(&self) -> bool { self.bytes.len() == 0 } - fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { !self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80) } - fn is_list(&self) -> bool { + pub fn is_list(&self) -> bool { !self.is_null() && self.bytes[0] >= 0xc0 } - fn is_data(&self) -> bool { + pub fn is_data(&self) -> bool { !self.is_null() && self.bytes[0] < 0xc0 } - fn is_int(&self) -> bool { + pub fn is_int(&self) -> bool { if self.is_null() { return false; } @@ -256,23 +248,32 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view { } } - fn iter(&'view self) -> Self::Iter { + pub fn iter(&'view self) -> UntrustedRlpIterator<'a, 'view> { self.into_iter() } - fn as_val(&self) -> Result where T: RlpDecodable { - // optimize, so it doesn't use clone (although This clone is cheap) - T::decode(&BasicDecoder::new(self.clone())) + pub fn as_val(&self) -> Result where T: Decodable { + T::decode(self) } - fn val_at(&self, index: usize) -> Result where T: RlpDecodable { + pub fn as_list(&self) -> Result, DecoderError> where T: Decodable { + self.iter().map(|rlp| rlp.as_val()).collect() + } + + pub fn val_at(&self, index: usize) -> Result where T: Decodable { self.at(index)?.as_val() } -} -impl<'a> UntrustedRlp<'a> { + pub fn list_at(&self, index: usize) -> Result, DecoderError> where T: Decodable { + self.at(index)?.as_list() + } + + pub fn decoder(&self) -> BasicDecoder { + BasicDecoder::new(self.clone()) + } + /// consumes first found prefix - fn consume_list_prefix(&self) -> Result<&'a [u8], DecoderError> { + fn consume_list_payload(&self) -> Result<&'a [u8], DecoderError> { let item = BasicDecoder::payload_info(self.bytes)?; let bytes = UntrustedRlp::consume(self.bytes, item.header_len)?; Ok(bytes) @@ -327,7 +328,7 @@ impl<'a, 'view> Iterator for UntrustedRlpIterator<'a, 'view> { } } -struct BasicDecoder<'a> { +pub struct BasicDecoder<'a> { rlp: UntrustedRlp<'a> } @@ -346,10 +347,8 @@ impl<'a> BasicDecoder<'a> { _ => Err(DecoderError::RlpIsTooShort), } } -} -impl<'a> Decoder for BasicDecoder<'a> { - fn read_value(&self, f: &F) -> Result + pub fn decode_value(&self, f: F) -> Result where F: Fn(&[u8]) -> Result { let bytes = self.rlp.as_raw(); @@ -378,7 +377,7 @@ impl<'a> Decoder for BasicDecoder<'a> { if bytes.len() < begin_of_value { return Err(DecoderError::RlpInconsistentLengthAndData); } - let len = usize::from_bytes(&bytes[1..begin_of_value])?; + let len = decode_usize(&bytes[1..begin_of_value])?; let last_index_of_value = begin_of_value + len; if bytes.len() < last_index_of_value { @@ -390,108 +389,12 @@ impl<'a> Decoder for BasicDecoder<'a> { _ => Err(DecoderError::RlpExpectedToBeData) } } - - fn as_raw(&self) -> &[u8] { - self.rlp.as_raw() - } - - fn as_rlp(&self) -> &UntrustedRlp { - &self.rlp - } -} - -impl Decodable for T where T: FromBytes { - fn decode(decoder: &D) -> Result where D: Decoder { - decoder.read_value(&|bytes: &[u8]| Ok(T::from_bytes(bytes)?)) - } -} - -impl Decodable for Vec where T: Decodable { - fn decode(decoder: &D) -> Result where D: Decoder { - decoder.as_rlp().iter().map(|d| T::decode(&BasicDecoder::new(d))).collect() - } -} - -impl Decodable for Option where T: Decodable { - fn decode(decoder: &D) -> Result where D: Decoder { - decoder.as_rlp().iter().map(|d| T::decode(&BasicDecoder::new(d))).collect::, DecoderError>>().map(|mut a| a.pop()) - } -} - -impl Decodable for Vec { - fn decode(decoder: &D) -> Result where D: Decoder { - decoder.read_value(&|bytes: &[u8]| Ok(bytes.to_vec())) - } -} - -macro_rules! impl_array_decodable { - ($index_type:ty, $len:expr ) => ( - impl Decodable for [T; $len] where T: Decodable { - fn decode(decoder: &D) -> Result where D: Decoder { - let decoders = decoder.as_rlp(); - - let mut result: [T; $len] = unsafe { ::std::mem::uninitialized() }; - if decoders.item_count() != $len { - return Err(DecoderError::RlpIncorrectListLen); - } - - for i in 0..decoders.item_count() { - result[i] = T::decode(&BasicDecoder::new(decoders.at(i)?))?; - } - - Ok(result) - } - } - ) -} - -macro_rules! impl_array_decodable_recursive { - ($index_type:ty, ) => (); - ($index_type:ty, $len:expr, $($more:expr,)*) => ( - impl_array_decodable!($index_type, $len); - impl_array_decodable_recursive!($index_type, $($more,)*); - ); -} - -impl_array_decodable_recursive!( - u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224, -); - -impl RlpDecodable for T where T: Decodable { - fn decode(decoder: &D) -> Result where D: Decoder { - Decodable::decode(decoder) - } -} - -struct DecodableU8 (u8); - -impl FromBytes for DecodableU8 { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - match bytes.len() { - 0 => Ok(DecodableU8(0u8)), - 1 => { - if bytes[0] == 0 { - return Err(FromBytesError::ZeroPrefixedInt) - } - Ok(DecodableU8(bytes[0])) - } - _ => Err(FromBytesError::DataIsTooLong) - } - } -} - -impl RlpDecodable for u8 { - fn decode(decoder: &D) -> Result where D: Decoder { - let u: DecodableU8 = Decodable::decode(decoder)?; - Ok(u.0) - } } #[cfg(test)] mod tests { - use ::{UntrustedRlp, View}; + use UntrustedRlp; + #[test] fn test_rlp_display() { use rustc_serialize::hex::FromHex; diff --git a/util/rlp/src/tests.rs b/util/rlp/tests/tests.rs similarity index 90% rename from util/rlp/src/tests.rs rename to util/rlp/tests/tests.rs index bd3abfe63..1c996caac 100644 --- a/util/rlp/src/tests.rs +++ b/util/rlp/tests/tests.rs @@ -14,9 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +extern crate ethcore_bigint as bigint; +extern crate rlp; + use std::{fmt, cmp}; use bigint::prelude::U256; -use {Encodable, RlpDecodable, UntrustedRlp, RlpStream, View, DecoderError}; +use rlp::{Encodable, Decodable, UntrustedRlp, RlpStream, DecoderError}; #[test] fn rlp_at() { @@ -24,7 +27,7 @@ fn rlp_at() { { let rlp = UntrustedRlp::new(&data); assert!(rlp.is_list()); - let animals: Vec = rlp.as_val().unwrap(); + let animals: Vec = rlp.as_list().unwrap(); assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]); let cat = rlp.at(0).unwrap(); @@ -89,7 +92,7 @@ fn run_encode_tests(tests: Vec>) where T: Encodable { for t in &tests { - let res = super::encode(&t.0); + let res = rlp::encode(&t.0); assert_eq!(&res[..], &t.1[..]); } } @@ -100,7 +103,7 @@ fn run_encode_tests_list(tests: Vec>) where T: Encodable { for t in &tests { - let res = super::encode_list(&t.0); + let res = rlp::encode_list(&t.0); assert_eq!(&res[..], &t.1[..]); } } @@ -210,11 +213,20 @@ fn encode_vector_str() { run_encode_tests_list(tests); } -struct DTestPair(T, Vec) where T: RlpDecodable + fmt::Debug + cmp::Eq; +struct DTestPair(T, Vec) where T: Decodable + fmt::Debug + cmp::Eq; -fn run_decode_tests(tests: Vec>) where T: RlpDecodable + fmt::Debug + cmp::Eq { +struct VDTestPair(Vec, Vec) where T: Decodable + fmt::Debug + cmp::Eq; + +fn run_decode_tests(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq { for t in &tests { - let res: T = super::decode(&t.1); + let res: T = rlp::decode(&t.1); + assert_eq!(res, t.0); + } +} + +fn run_decode_tests_list(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq { + for t in &tests { + let res: Vec = rlp::decode_list(&t.1); assert_eq!(res, t.0); } } @@ -318,35 +330,19 @@ fn decode_untrusted_address() { #[test] fn decode_untrusted_vector_u64() { let tests = vec![ - DTestPair(vec![], vec![0xc0]), - DTestPair(vec![15u64], vec![0xc1, 0x0f]), - DTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - DTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), + VDTestPair(vec![], vec![0xc0]), + VDTestPair(vec![15u64], vec![0xc1, 0x0f]), + VDTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), + VDTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), ]; - run_decode_tests(tests); + run_decode_tests_list(tests); } #[test] fn decode_untrusted_vector_str() { - let tests = vec![DTestPair(vec!["cat".to_owned(), "dog".to_owned()], + let tests = vec![VDTestPair(vec!["cat".to_owned(), "dog".to_owned()], vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; - run_decode_tests(tests); -} - -#[test] -fn decode_untrusted_vector_of_vectors_str() { - let tests = vec![DTestPair(vec![vec!["cat".to_owned()]], - vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])]; - run_decode_tests(tests); -} - -#[test] -fn test_decoding_array() { - let v = vec![5u16, 2u16]; - let res = super::encode_list(&v); - let arr: [u16; 2] = super::decode(&res); - assert_eq!(arr[0], 5); - assert_eq!(arr[1], 2); + run_decode_tests_list(tests); } #[test] diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index bd05d5fc1..66e5a1cfd 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -290,7 +290,7 @@ impl EarlyMergeDB { &r.drain() }).expect("Low-level database error.") { let rlp = Rlp::new(&rlp_data); - let inserts: Vec = rlp.val_at(1); + let inserts: Vec = rlp.list_at(1); Self::replay_keys(&inserts, db, col, &mut refs); index += 1; }; @@ -466,11 +466,11 @@ impl JournalDB for EarlyMergeDB { &last })? { let rlp = Rlp::new(&rlp_data); - let inserts: Vec = rlp.val_at(1); + let inserts: Vec = rlp.list_at(1); if canon_id == &rlp.val_at::(0) { // Collect keys to be removed. Canon block - remove the (enacted) deletes. - let deletes: Vec = rlp.val_at(2); + let deletes: Vec = rlp.list_at(2); trace!(target: "jdb.ops", " Expunging: {:?}", deletes); Self::remove_keys(&deletes, &mut refs, batch, self.column, RemoveFrom::Archive, trace); diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index e8095e71e..7eeabf6df 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -155,7 +155,7 @@ impl OverlayRecentDB { let rlp = Rlp::new(&rlp_data); let id: H256 = rlp.val_at(0); let insertions = rlp.at(1); - let deletions: Vec = rlp.val_at(2); + let deletions: Vec = rlp.list_at(2); let mut inserted_keys = Vec::new(); for r in insertions.iter() { let k: H256 = r.val_at(0); diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index b18954eb3..13c2189c8 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -171,7 +171,7 @@ impl JournalDB for RefCountedDB { } { let rlp = Rlp::new(&rlp_data); let our_id: H256 = rlp.val_at(0); - let to_remove: Vec = rlp.val_at(if *canon_id == our_id {2} else {1}); + let to_remove: Vec = rlp.list_at(if *canon_id == our_id {2} else {1}); trace!(target: "rcdb", "delete journal for time #{}.{}=>{}, (canon was {}): deleting {:?}", end_era, index, our_id, canon_id, to_remove); for i in &to_remove { self.forward.remove(i); diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index 043b3d983..7de8dc910 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -23,7 +23,7 @@ use std::path::PathBuf; use common::*; use elastic_array::*; use hashdb::DBValue; -use rlp::{UntrustedRlp, RlpType, View, Compressible}; +use rlp::{UntrustedRlp, RlpType, Compressible}; use rocksdb::{DB, Writable, WriteBatch, WriteOptions, IteratorMode, DBIterator, Options, DBCompactionStyle, BlockBasedOptions, Direction, Cache, Column, ReadOptions}; #[cfg(target_os = "linux")] diff --git a/util/src/trie/lookup.rs b/util/src/trie/lookup.rs index 30e021527..d24a82e16 100644 --- a/util/src/trie/lookup.rs +++ b/util/src/trie/lookup.rs @@ -18,7 +18,7 @@ use hashdb::HashDB; use nibbleslice::NibbleSlice; -use rlp::{Rlp, View}; +use rlp::Rlp; use ::{H256}; use super::{TrieError, Query}; diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index c5f2a739b..2c2e556c5 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -24,7 +24,7 @@ use super::node::NodeKey; use ::{HashDB, H256}; use ::bytes::ToPretty; use ::nibbleslice::NibbleSlice; -use ::rlp::{Rlp, RlpStream, View}; +use ::rlp::{Rlp, RlpStream}; use ::sha3::SHA3_NULL_RLP; use hashdb::DBValue;