diff --git a/Cargo.lock b/Cargo.lock index fff7d286..e47785a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,6 +173,7 @@ name = "db" version = "0.1.0" dependencies = [ "bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcrypto 0.1.0", "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "chain 0.1.0", "elastic-array 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index 5fed6d43..02a11c3f 100644 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -2,11 +2,11 @@ extern crate crypto as rcrypto; extern crate primitives; extern crate siphasher; +pub use rcrypto::digest::Digest; use std::hash::Hasher; use rcrypto::sha1::Sha1; use rcrypto::sha2::Sha256; use rcrypto::ripemd160::Ripemd160; -use rcrypto::digest::Digest; use siphasher::sip::SipHasher24; use primitives::hash::{H32, H160, H256}; @@ -72,6 +72,12 @@ impl DHash256 { pub fn new() -> Self { DHash256::default() } + + pub fn finish(mut self) -> H256 { + let mut result = H256::default(); + self.result(&mut *result); + result + } } impl Digest for DHash256 { diff --git a/db/Cargo.toml b/db/Cargo.toml index dd92e8d1..e27e490f 100644 --- a/db/Cargo.toml +++ b/db/Cargo.toml @@ -8,6 +8,7 @@ elastic-array = "0.5" rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" } ethcore-devtools = { path = "../devtools" } primitives = { path = "../primitives" } +bitcrypto = { path = "../crypto" } byteorder = "0.5" chain = { path = "../chain" } serialization = { path = "../serialization" } diff --git a/db/src/indexed_block.rs b/db/src/indexed_block.rs index dee6936b..9b10f08a 100644 --- a/db/src/indexed_block.rs +++ b/db/src/indexed_block.rs @@ -1,6 +1,10 @@ +use std::io; use primitives::hash::H256; use chain::{Block, OutPoint, TransactionOutput, merkle_root, Transaction}; -use serialization::{Serializable, serialized_list_size}; +use serialization::{ + Serializable, serialized_list_size, + Deserializable, Reader, Error as ReaderError +}; use indexed_header::IndexedBlockHeader; use indexed_transaction::IndexedTransaction; use {TransactionOutputObserver, PreviousTransactionOutputProvider}; @@ -87,3 +91,14 @@ impl IndexedBlock { self.transactions.iter().all(|tx| tx.raw.is_final(height, self.header.raw.time)) } } + +impl Deserializable for IndexedBlock { + fn deserialize(reader: &mut Reader) -> Result where T: io::Read { + let block = IndexedBlock { + header: try!(reader.read()), + transactions: try!(reader.read_list()), + }; + + Ok(block) + } +} diff --git a/db/src/indexed_header.rs b/db/src/indexed_header.rs index df117833..04dfc9d8 100644 --- a/db/src/indexed_header.rs +++ b/db/src/indexed_header.rs @@ -1,5 +1,8 @@ +use std::io; use primitives::hash::H256; use chain::BlockHeader; +use serialization::{Deserializable, Reader, Error as ReaderError}; +use read_and_hash::ReadAndHash; #[derive(Debug, Clone)] pub struct IndexedBlockHeader { @@ -24,3 +27,16 @@ impl IndexedBlockHeader { } } } + +impl Deserializable for IndexedBlockHeader { + fn deserialize(reader: &mut Reader) -> Result where T: io::Read { + let data = try!(reader.read_and_hash::()); + // TODO: use len + let header = IndexedBlockHeader { + raw: data.data, + hash: data.hash, + }; + + Ok(header) + } +} diff --git a/db/src/indexed_transaction.rs b/db/src/indexed_transaction.rs index bcfec139..899da6a7 100644 --- a/db/src/indexed_transaction.rs +++ b/db/src/indexed_transaction.rs @@ -1,6 +1,8 @@ -use std::cmp; +use std::{cmp, io}; use primitives::hash::H256; use chain::{Transaction, OutPoint, TransactionOutput}; +use serialization::{Deserializable, Reader, Error as ReaderError}; +use read_and_hash::ReadAndHash; use PreviousTransactionOutputProvider; #[derive(Debug, Clone)] @@ -33,6 +35,19 @@ impl cmp::PartialEq for IndexedTransaction { } } +impl Deserializable for IndexedTransaction { + fn deserialize(reader: &mut Reader) -> Result where T: io::Read { + let data = try!(reader.read_and_hash::()); + // TODO: use len + let tx = IndexedTransaction { + raw: data.data, + hash: data.hash, + }; + + Ok(tx) + } +} + impl<'a> PreviousTransactionOutputProvider for &'a [IndexedTransaction] { fn previous_transaction_output(&self, prevout: &OutPoint) -> Option { self.iter() diff --git a/db/src/lib.rs b/db/src/lib.rs index 10a05309..cb2eba41 100644 --- a/db/src/lib.rs +++ b/db/src/lib.rs @@ -1,5 +1,6 @@ //! Bitcoin database +extern crate bitcrypto as crypto; extern crate elastic_array; extern crate rocksdb; extern crate parking_lot; @@ -31,6 +32,7 @@ mod update_context; mod indexed_block; mod indexed_header; mod indexed_transaction; +mod read_and_hash; #[derive(Debug, Clone)] pub enum BlockRef { diff --git a/db/src/read_and_hash.rs b/db/src/read_and_hash.rs new file mode 100644 index 00000000..8be41f10 --- /dev/null +++ b/db/src/read_and_hash.rs @@ -0,0 +1,33 @@ +use std::io; +use crypto::{DHash256, Digest}; +use primitives::hash::H256; +use serialization::{Reader, Error as ReaderError, Deserializable}; + +pub struct HashedData { + pub len: usize, + pub hash: H256, + pub data: T, +} + +pub trait ReadAndHash { + fn read_and_hash(&mut self) -> Result, ReaderError> where T: Deserializable; +} + +impl ReadAndHash for Reader where R: io::Read { + fn read_and_hash(&mut self) -> Result, ReaderError> where T: Deserializable { + let mut len = 0usize; + let mut hasher = DHash256::new(); + let data = self.read_with_proxy(|bytes| { + len += bytes.len(); + hasher.input(bytes); + })?; + + let result = HashedData { + hash: hasher.finish(), + data: data, + len: len, + }; + + Ok(result) + } +} diff --git a/serialization/src/reader.rs b/serialization/src/reader.rs index 51dacb61..653a99b5 100644 --- a/serialization/src/reader.rs +++ b/serialization/src/reader.rs @@ -84,6 +84,11 @@ impl Reader where R: io::Read { T::deserialize(self) } + pub fn read_with_proxy(&mut self, proxy: F) -> Result where T: Deserializable, F: FnMut(&[u8]) { + let mut reader = Reader::from_read(Proxy::new(self, proxy)); + T::deserialize(&mut reader) + } + pub fn read_slice(&mut self, bytes: &mut [u8]) -> Result<(), Error> { io::Read::read_exact(self, bytes).map_err(|_| Error::UnexpectedEnd) } @@ -148,3 +153,26 @@ impl Iterator for ReadIterator where R: io::Read, T: Deserializable } } } + +struct Proxy { + from: F, + to: T, +} + +impl Proxy { + fn new(from: F, to: T) -> Self { + Proxy { + from: from, + to: to, + } + } +} + +impl io::Read for Proxy where F: io::Read, T: FnMut(&[u8]) { + fn read(&mut self, buf: &mut [u8]) -> Result { + let len = try!(io::Read::read(&mut self.from, buf)); + let to = &mut self.to; + to(&buf[..len]); + Ok(len) + } +}