diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 6e9e04e85..8522ebd40 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -17,6 +17,7 @@ //! Blockchain database client. use std::marker::PhantomData; +use std::fs::{create_dir, File}; use std::path::PathBuf; use util::*; use util::panics::*; @@ -755,33 +756,39 @@ impl BlockChainClient for Client where V: Verifier { } fn take_snapshot(&self, root_dir: &Path) { - use pv64::BlockChunker; + use pv64::{BlockChunker, ManifestData}; let best_header_bytes = self.best_block_header(); let best_header = HeaderView::new(&best_header_bytes); + let state_root = best_header.state_root(); trace!(target: "pv64_snapshot", "Taking snapshot starting at block {}", best_header.number()); - let mut manifest_hashes = Vec::new(); - // lock the state db while we create the state chunks. - { + let state_hashes = { let _state_db = self.state_db.lock().unwrap(); - let _state_root = best_header.state_root(); // todo [rob] actually create the state chunks. - } + + Vec::new() + }; let best_hash = best_header.hash(); let genesis_hash = self.chain.genesis_hash(); let mut path = root_dir.to_owned(); path.push("snapshot/"); - let _ = ::std::fs::create_dir(&path); + let _ = create_dir(&path); let block_chunk_hashes = BlockChunker::new(self, best_hash, genesis_hash).chunk_all(&path); - for hash in block_chunk_hashes { - manifest_hashes.push(hash); - } + + let manifest_data = ManifestData { + state_hashes: state_hashes, + block_hashes: block_chunk_hashes, + state_root: state_root, + }; + + let mut manifest_file = File::create("MANIFEST").unwrap(); + manifest_file.write_all(&manifest_data.to_rlp()).unwrap(); } } diff --git a/ethcore/src/pv64/mod.rs b/ethcore/src/pv64/mod.rs index 13b39f983..cf9e161c4 100644 --- a/ethcore/src/pv64/mod.rs +++ b/ethcore/src/pv64/mod.rs @@ -30,7 +30,7 @@ use views::BlockView; use util::{Bytes, Hashable}; use util::hash::H256; -use util::rlp::{Stream, RlpStream}; +use util::rlp::{DecoderError, Stream, RlpStream, UntrustedRlp, View}; /// Used to build block chunks. pub struct BlockChunker<'a> { @@ -123,4 +123,41 @@ impl<'a> BlockChunker<'a> { chunk_hashes } +} + +/// Manifest data. +pub struct ManifestData { + /// List of state chunk hashes. + pub state_hashes: Vec, + /// List of block chunk hashes. + pub block_hashes: Vec, + /// The final, expected state root. + pub state_root: H256, +} + +impl ManifestData { + /// Encode the manifest data to. + pub fn to_rlp(self) -> Bytes { + let mut stream = RlpStream::new_list(3); + stream.append(&self.state_hashes); + stream.append(&self.block_hashes); + stream.append(&self.state_root); + + stream.out() + } + + /// Try to restore manifest data from raw bytes interpreted as RLP. + pub fn from_rlp(raw: &[u8]) -> Result { + let decoder = UntrustedRlp::new(raw); + + let state_hashes: Vec = try!(try!(decoder.at(0)).as_val()); + let block_hashes: Vec = try!(try!(decoder.at(1)).as_val()); + let state_root: H256 = try!(try!(decoder.at(2)).as_val()); + + Ok(ManifestData { + state_hashes: state_hashes, + block_hashes: block_hashes, + state_root: state_root, + }) + } } \ No newline at end of file