State db sync

This commit is contained in:
arkpar 2016-01-14 01:28:37 +01:00
parent d3a16574d6
commit 8f631a7c60
3 changed files with 55 additions and 13 deletions

View File

@ -1,4 +1,5 @@
use util::*; use util::*;
use rocksdb::{DB};
use blockchain::{BlockChain, BlockProvider}; use blockchain::{BlockChain, BlockProvider};
use views::BlockView; use views::BlockView;
use error::*; use error::*;
@ -7,6 +8,9 @@ use spec::Spec;
use engine::Engine; use engine::Engine;
use queue::BlockQueue; use queue::BlockQueue;
use sync::NetSyncMessage; use sync::NetSyncMessage;
use env_info::LastHashes;
use verification::*;
use block::*;
/// General block status /// General block status
pub enum BlockStatus { pub enum BlockStatus {
@ -95,7 +99,8 @@ pub trait BlockChainClient : Sync {
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
pub struct Client { pub struct Client {
chain: Arc<RwLock<BlockChain>>, chain: Arc<RwLock<BlockChain>>,
_engine: Arc<Box<Engine>>, engine: Arc<Box<Engine>>,
state_db: OverlayDB,
queue: BlockQueue, queue: BlockQueue,
} }
@ -103,15 +108,56 @@ impl Client {
pub fn new(spec: Spec, path: &Path, message_channel: IoChannel<NetSyncMessage> ) -> Result<Client, Error> { pub fn new(spec: Spec, path: &Path, message_channel: IoChannel<NetSyncMessage> ) -> Result<Client, Error> {
let chain = Arc::new(RwLock::new(BlockChain::new(&spec.genesis_block(), path))); let chain = Arc::new(RwLock::new(BlockChain::new(&spec.genesis_block(), path)));
let engine = Arc::new(try!(spec.to_engine())); let engine = Arc::new(try!(spec.to_engine()));
let mut state_path = path.to_path_buf();
state_path.push("state");
let db = DB::open_default(state_path.to_str().unwrap()).unwrap();
Ok(Client { Ok(Client {
chain: chain.clone(), chain: chain.clone(),
_engine: engine.clone(), engine: engine.clone(),
queue: BlockQueue::new(chain.clone(), engine.clone(), message_channel), state_db: OverlayDB::new(db),
queue: BlockQueue::new(engine.clone(), message_channel),
}) })
} }
pub fn import_verified_block(&mut self, bytes: Bytes) { pub fn import_verified_block(&mut self, bytes: Bytes) {
let block = BlockView::new(&bytes);
let header = block.header_view();
if let Err(e) = verify_block_final(&bytes, self.engine.deref().deref(), self.chain.read().unwrap().deref()) {
warn!(target: "client", "Stage 3 block verification failed for {}\nError: {:?}", header.sha3(), e);
// TODO: mark as bad
return;
};
let parent = match self.chain.read().unwrap().block_header(&header.parent_hash()) {
Some(p) => p,
None => {
warn!(target: "client", "Stage 3 import failed for {}: Parent not found ({}) ", header.sha3(), header.parent_hash());
return;
},
};
// build last hashes
let mut last = self.chain.read().unwrap().best_block_hash();
let mut last_hashes = LastHashes::new();
last_hashes.resize(256, H256::new());
for i in 0..255 {
match self.chain.read().unwrap().block_details(&last) {
Some(details) => {
last_hashes[i + 1] = details.parent.clone();
last = details.parent.clone();
},
None => break,
}
}
let mut b = OpenBlock::new(self.engine.deref().deref(), self.state_db.clone(), &parent, &last_hashes, header.author(), header.extra_data());
for t in block.transactions().into_iter() {
if let Err(e) = b.push_transaction(t.clone(), None) {
warn!(target: "client", "Stage 3 transaction import failed for block {}\nTransaction:{:?}\nError: {:?}", header.sha3(), t, e);
return;
};
}
self.chain.write().unwrap().insert_block(&bytes); self.chain.write().unwrap().insert_block(&bytes);
} }
} }
@ -171,6 +217,10 @@ impl BlockChainClient for Client {
} }
fn import_block(&mut self, bytes: &[u8]) -> ImportResult { fn import_block(&mut self, bytes: &[u8]) -> ImportResult {
let header = BlockView::new(bytes).header();
if self.chain.read().unwrap().is_known(&header.hash()) {
return Err(ImportError::AlreadyInChain);
}
self.queue.import_block(bytes) self.queue.import_block(bytes)
} }

View File

@ -1,6 +1,4 @@
use util::*; use util::*;
use blockchain::*;
use views::{BlockView};
use verification::*; use verification::*;
use error::*; use error::*;
use engine::Engine; use engine::Engine;
@ -9,16 +7,14 @@ use sync::*;
/// A queue of blocks. Sits between network or other I/O and the BlockChain. /// A queue of blocks. Sits between network or other I/O and the BlockChain.
/// Sorts them ready for blockchain insertion. /// Sorts them ready for blockchain insertion.
pub struct BlockQueue { pub struct BlockQueue {
bc: Arc<RwLock<BlockChain>>,
engine: Arc<Box<Engine>>, engine: Arc<Box<Engine>>,
message_channel: IoChannel<NetSyncMessage> message_channel: IoChannel<NetSyncMessage>
} }
impl BlockQueue { impl BlockQueue {
/// Creates a new queue instance. /// Creates a new queue instance.
pub fn new(bc: Arc<RwLock<BlockChain>>, engine: Arc<Box<Engine>>, message_channel: IoChannel<NetSyncMessage>) -> BlockQueue { pub fn new(engine: Arc<Box<Engine>>, message_channel: IoChannel<NetSyncMessage>) -> BlockQueue {
BlockQueue { BlockQueue {
bc: bc,
engine: engine, engine: engine,
message_channel: message_channel message_channel: message_channel
} }
@ -30,13 +26,8 @@ impl BlockQueue {
/// Add a block to the queue. /// Add a block to the queue.
pub fn import_block(&mut self, bytes: &[u8]) -> ImportResult { pub fn import_block(&mut self, bytes: &[u8]) -> ImportResult {
let header = BlockView::new(bytes).header();
if self.bc.read().unwrap().is_known(&header.hash()) {
return Err(ImportError::AlreadyInChain);
}
try!(verify_block_basic(bytes, self.engine.deref().deref())); try!(verify_block_basic(bytes, self.engine.deref().deref()));
try!(verify_block_unordered(bytes, self.engine.deref().deref())); try!(verify_block_unordered(bytes, self.engine.deref().deref()));
try!(verify_block_final(bytes, self.engine.deref().deref(), self.bc.read().unwrap().deref()));
try!(self.message_channel.send(UserMessage(SyncMessage::BlockVerified(bytes.to_vec()))).map_err(|e| Error::from(e))); try!(self.message_channel.send(UserMessage(SyncMessage::BlockVerified(bytes.to_vec()))).map_err(|e| Error::from(e)));
Ok(()) Ok(())
} }

View File

@ -38,6 +38,7 @@ pub fn verify_block_unordered(bytes: &[u8], engine: &Engine) -> Result<(), Error
/// Phase 3 verification. Check block information against parent and uncles. /// Phase 3 verification. Check block information against parent and uncles.
pub fn verify_block_final<BC>(bytes: &[u8], engine: &Engine, bc: &BC) -> Result<(), Error> where BC: BlockProvider { pub fn verify_block_final<BC>(bytes: &[u8], engine: &Engine, bc: &BC) -> Result<(), Error> where BC: BlockProvider {
// TODO: verify timestamp
let block = BlockView::new(bytes); let block = BlockView::new(bytes);
let header = block.header(); let header = block.header();
let parent = try!(bc.block_header(&header.parent_hash).ok_or::<Error>(From::from(BlockError::UnknownParent(header.parent_hash.clone())))); let parent = try!(bc.block_header(&header.parent_hash).ok_or::<Error>(From::from(BlockError::UnknownParent(header.parent_hash.clone()))));