Newer
Older
use util::*;
use header::BlockNumber;
use env_info::LastHashes;
use verification::*;
use block::*;
/// General block status
pub enum BlockStatus {
/// Part of the blockchain.
InChain,
/// Queued for import.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/// Known as bad.
Bad,
/// Unknown.
Unknown,
}
/// Information about the blockchain gthered together.
pub struct BlockChainInfo {
/// Blockchain difficulty.
pub total_difficulty: U256,
/// Block queue difficulty.
pub pending_total_difficulty: U256,
/// Genesis block hash.
pub genesis_hash: H256,
/// Best blockchain block hash.
pub best_block_hash: H256,
/// Best blockchain block number.
pub best_block_number: BlockNumber
}
/// Block queue status
pub struct BlockQueueStatus {
pub full: bool,
}
pub type TreeRoute = ::blockchain::TreeRoute;
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync {
/// Get raw block header data by block header hash.
fn block_header(&self, hash: &H256) -> Option<Bytes>;
/// Get raw block body data by block header hash.
/// Block body is an RLP list of two items: uncles and transactions.
fn block_body(&self, hash: &H256) -> Option<Bytes>;
/// Get raw block data by block header hash.
fn block(&self, hash: &H256) -> Option<Bytes>;
/// Get block status by block header hash.
fn block_status(&self, hash: &H256) -> BlockStatus;
/// Get raw block header data by block number.
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes>;
/// Get raw block body data by block number.
/// Block body is an RLP list of two items: uncles and transactions.
fn block_body_at(&self, n: BlockNumber) -> Option<Bytes>;
/// Get raw block data by block number.
fn block_at(&self, n: BlockNumber) -> Option<Bytes>;
/// Get block status by block number.
fn block_status_at(&self, n: BlockNumber) -> BlockStatus;
/// Get a tree route between `from` and `to`.
/// See `BlockChain::tree_route`.
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute>;
/// Get latest state node
fn state_data(&self, hash: &H256) -> Option<Bytes>;
/// Get raw block receipts data by block header hash.
fn block_receipts(&self, hash: &H256) -> Option<Bytes>;
/// Import a block into the blockchain.
fn import_block(&mut self, byte: &[u8]) -> ImportResult;
/// Get block queue information.
fn queue_status(&self) -> BlockQueueStatus;
/// Clear block queue and abort all import activity.
fn clear_queue(&mut self);
/// Get blockchain information.
fn chain_info(&self) -> BlockChainInfo;
}
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
pub struct Client {
chain: Arc<RwLock<BlockChain>>,
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 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();
engine: engine.clone(),
state_db: OverlayDB::new(db),
queue: BlockQueue::new(engine.clone(), message_channel),
pub fn import_verified_block(&mut self, bytes: Bytes) {
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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);
}
}
impl BlockChainClient for Client {
fn block_header(&self, hash: &H256) -> Option<Bytes> {
self.chain.read().unwrap().block(hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())
}
fn block_body(&self, hash: &H256) -> Option<Bytes> {
self.chain.read().unwrap().block(hash).map(|bytes| {
let rlp = Rlp::new(&bytes);
let mut body = RlpStream::new();
body.append_raw(rlp.at(1).as_raw(), 1);
body.append_raw(rlp.at(2).as_raw(), 1);
body.out()
})
}
fn block(&self, hash: &H256) -> Option<Bytes> {
self.chain.read().unwrap().block(hash)
}
fn block_status(&self, hash: &H256) -> BlockStatus {
if self.chain.read().unwrap().is_known(&hash) { BlockStatus::InChain } else { BlockStatus::Unknown }
}
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes> {
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h))
}
fn block_body_at(&self, n: BlockNumber) -> Option<Bytes> {
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_body(&h))
}
fn block_at(&self, n: BlockNumber) -> Option<Bytes> {
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block(&h))
}
fn block_status_at(&self, n: BlockNumber) -> BlockStatus {
match self.chain.read().unwrap().block_hash(n) {
Some(h) => self.block_status(&h),
None => BlockStatus::Unknown
}
}
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
self.chain.read().unwrap().tree_route(from.clone(), to.clone())
}
fn state_data(&self, _hash: &H256) -> Option<Bytes> {
unimplemented!();
}
fn block_receipts(&self, _hash: &H256) -> Option<Bytes> {
unimplemented!();
}
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)
}
fn queue_status(&self) -> BlockQueueStatus {
BlockQueueStatus {
full: false
}
}
fn clear_queue(&mut self) {
}
fn chain_info(&self) -> BlockChainInfo {
let chain = self.chain.read().unwrap();
total_difficulty: chain.best_block_total_difficulty(),
pending_total_difficulty: chain.best_block_total_difficulty(),
genesis_hash: chain.genesis_hash(),
best_block_hash: chain.best_block_hash(),
best_block_number: From::from(chain.best_block_number())