Skip to content

Commit 0ebd568

Browse files
remagpieforiequal0
authored andcommitted
Import snapshot block with body
1 parent 2995012 commit 0ebd568

File tree

6 files changed

+146
-77
lines changed

6 files changed

+146
-77
lines changed

core/src/blockchain/blockchain.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,6 @@ impl BlockChain {
9898
}
9999
}
100100

101-
pub fn insert_bootstrap_header(&self, batch: &mut DBTransaction, header: &HeaderView) {
102-
self.headerchain.insert_bootstrap_header(batch, header);
103-
104-
let hash = header.hash();
105-
106-
*self.pending_best_block_hash.write() = Some(hash);
107-
batch.put(db::COL_EXTRA, BEST_BLOCK_KEY, &hash);
108-
109-
*self.pending_best_proposal_block_hash.write() = Some(hash);
110-
batch.put(db::COL_EXTRA, BEST_PROPOSAL_BLOCK_KEY, &hash);
111-
}
112-
113101
pub fn insert_header(
114102
&self,
115103
batch: &mut DBTransaction,
@@ -122,6 +110,34 @@ impl BlockChain {
122110
}
123111
}
124112

113+
pub fn insert_bootstrap_block(&self, batch: &mut DBTransaction, bytes: &[u8]) {
114+
let block = BlockView::new(bytes);
115+
let header = block.header_view();
116+
let hash = header.hash();
117+
118+
ctrace!(BLOCKCHAIN, "Inserting bootstrap block #{}({}) to the blockchain.", header.number(), hash);
119+
120+
if self.is_known(&hash) {
121+
cdebug!(BLOCKCHAIN, "Block #{}({}) is already known.", header.number(), hash);
122+
return
123+
}
124+
125+
assert!(self.pending_best_block_hash.read().is_none());
126+
assert!(self.pending_best_proposal_block_hash.read().is_none());
127+
128+
self.headerchain.insert_bootstrap_header(batch, &header);
129+
self.body_db.insert_body(batch, &block);
130+
self.body_db.update_best_block(batch, &BestBlockChanged::CanonChainAppended {
131+
best_block: bytes.to_vec(),
132+
});
133+
134+
*self.pending_best_block_hash.write() = Some(hash);
135+
batch.put(db::COL_EXTRA, BEST_BLOCK_KEY, &hash);
136+
137+
*self.pending_best_proposal_block_hash.write() = Some(hash);
138+
batch.put(db::COL_EXTRA, BEST_PROPOSAL_BLOCK_KEY, &hash);
139+
}
140+
125141
/// Inserts the block into backing cache database.
126142
/// Expects the block to be valid and already verified.
127143
/// If the block is already known, does nothing.

core/src/client/client.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use cstate::{
2828
};
2929
use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken};
3030
use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction};
31-
use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash};
31+
use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash};
3232
use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig};
3333
use hashdb::AsHashDB;
3434
use journaldb;
@@ -43,7 +43,7 @@ use super::{
4343
ClientConfig, DatabaseClient, EngineClient, EngineInfo, Error as ClientError, ExecuteClient, ImportBlock,
4444
ImportResult, MiningBlockChainClient, Shard, StateInfo, StateOrBlock, TextClient,
4545
};
46-
use crate::block::{ClosedBlock, IsBlock, OpenBlock, SealedBlock};
46+
use crate::block::{Block, ClosedBlock, IsBlock, OpenBlock, SealedBlock};
4747
use crate::blockchain::{BlockChain, BlockProvider, BodyProvider, HeaderProvider, InvoiceProvider, TransactionAddress};
4848
use crate::client::{ConsensusClient, SnapshotClient, TermInfo};
4949
use crate::consensus::{CodeChainEngine, EngineError};
@@ -664,13 +664,13 @@ impl ImportBlock for Client {
664664
Ok(self.importer.header_queue.import(unverified)?)
665665
}
666666

667-
fn import_bootstrap_header(&self, header: &Header) -> Result<BlockHash, BlockImportError> {
668-
if self.block_chain().is_known_header(&header.hash()) {
667+
fn import_bootstrap_block(&self, block: &Block) -> Result<BlockHash, BlockImportError> {
668+
if self.block_chain().is_known(&block.header.hash()) {
669669
return Err(BlockImportError::Import(ImportError::AlreadyInChain))
670670
}
671671
let import_lock = self.importer.import_lock.lock();
672-
self.importer.import_bootstrap_header(header, self, &import_lock);
673-
Ok(header.hash())
672+
self.importer.import_bootstrap_block(block, self, &import_lock);
673+
Ok(block.header.hash())
674674
}
675675

676676
fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult {

core/src/client/importer.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ use std::sync::Arc;
2020
use std::time::Instant;
2121

2222
use cio::IoChannel;
23-
use ctypes::header::Header;
23+
use ctypes::header::{Header, Seal};
2424
use ctypes::BlockHash;
2525
use kvdb::DBTransaction;
2626
use parking_lot::{Mutex, MutexGuard};
2727
use rlp::Encodable;
2828

2929
use super::{BlockChainTrait, Client, ClientConfig};
30-
use crate::block::{enact, IsBlock, LockedBlock};
30+
use crate::block::{enact, Block, IsBlock, LockedBlock};
3131
use crate::blockchain::{BodyProvider, HeaderProvider, ImportRoute};
3232
use crate::consensus::CodeChainEngine;
3333
use crate::error::Error;
@@ -371,19 +371,26 @@ impl Importer {
371371
imported.len()
372372
}
373373

374-
pub fn import_bootstrap_header<'a>(&'a self, header: &'a Header, client: &Client, _importer_lock: &MutexGuard<()>) {
374+
pub fn import_bootstrap_block<'a>(&'a self, block: &'a Block, client: &Client, _importer_lock: &MutexGuard<()>) {
375+
let header = &block.header;
375376
let hash = header.hash();
376-
ctrace!(CLIENT, "Importing bootstrap header {}-{:?}", header.number(), hash);
377+
ctrace!(CLIENT, "Importing bootstrap block #{}-{:?}", header.number(), hash);
377378

379+
let start = Instant::now();
378380
{
379381
let chain = client.block_chain();
380382
let mut batch = DBTransaction::new();
381-
chain.insert_bootstrap_header(&mut batch, &HeaderView::new(&header.rlp_bytes()));
383+
chain.insert_bootstrap_block(&mut batch, &block.rlp_bytes(&Seal::With));
382384
client.db().write_buffered(batch);
383385
chain.commit();
384386
}
385-
387+
let duration = {
388+
let elapsed = start.elapsed();
389+
elapsed.as_secs() * 1_000_000_000 + u64::from(elapsed.subsec_nanos())
390+
};
386391
client.new_headers(&[hash], &[], &[hash], &[], &[], 0, Some(hash));
392+
self.miner.chain_new_blocks(client, &[hash], &[], &[hash], &[]);
393+
client.new_blocks(&[hash], &[], &[hash], &[], &[], duration);
387394

388395
client.db().flush().expect("DB flush failed.");
389396
}

core/src/client/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ use cmerkle::Result as TrieResult;
3838
use cnetwork::NodeId;
3939
use cstate::{AssetScheme, FindActionHandler, OwnedAsset, StateResult, Text, TopLevelState, TopStateView};
4040
use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction};
41-
use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash};
41+
use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash};
4242
use cvm::ChainTimeInfo;
4343
use kvdb::KeyValueDB;
4444
use primitives::{Bytes, H160, H256, U256};
4545

46-
use crate::block::{ClosedBlock, OpenBlock, SealedBlock};
46+
use crate::block::{Block, ClosedBlock, OpenBlock, SealedBlock};
4747
use crate::blockchain_info::BlockChainInfo;
4848
use crate::consensus::EngineError;
4949
use crate::encoded;
@@ -203,7 +203,7 @@ pub trait ImportBlock {
203203

204204
/// Import a trusted bootstrap header into the blockchain
205205
/// Bootstrap headers don't execute any verifications
206-
fn import_bootstrap_header(&self, bytes: &Header) -> Result<BlockHash, BlockImportError>;
206+
fn import_bootstrap_block(&self, bytes: &Block) -> Result<BlockHash, BlockImportError>;
207207

208208
/// Import sealed block. Skips all verifications.
209209
fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult;

core/src/client/test_client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use parking_lot::RwLock;
5252
use primitives::{Bytes, H256, U256};
5353
use rlp::*;
5454

55-
use crate::block::{ClosedBlock, OpenBlock, SealedBlock};
55+
use crate::block::{Block, ClosedBlock, OpenBlock, SealedBlock};
5656
use crate::blockchain_info::BlockChainInfo;
5757
use crate::client::ImportResult;
5858
use crate::client::{
@@ -510,7 +510,7 @@ impl ImportBlock for TestBlockChainClient {
510510
unimplemented!()
511511
}
512512

513-
fn import_bootstrap_header(&self, _header: &BlockHeader) -> Result<BlockHash, BlockImportError> {
513+
fn import_bootstrap_block(&self, _header: &Block) -> Result<BlockHash, BlockImportError> {
514514
unimplemented!()
515515
}
516516

sync/src/block/extension.rs

Lines changed: 94 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use ccore::{
2727
};
2828
use cmerkle::snapshot::ChunkDecompressor;
2929
use cmerkle::snapshot::Restore as SnapshotRestore;
30-
use cmerkle::TrieFactory;
30+
use cmerkle::{skewed_merkle_root, TrieFactory};
3131
use cnetwork::{Api, EventSender, NetworkExtension, NodeId};
3232
use cstate::FindActionHandler;
3333
use ctimer::TimerToken;
@@ -64,7 +64,7 @@ pub struct TokenInfo {
6464
enum State {
6565
SnapshotHeader(BlockHash, u64),
6666
SnapshotBody {
67-
block: BlockHash,
67+
header: EncodedHeader,
6868
prev_root: H256,
6969
},
7070
SnapshotChunk {
@@ -150,7 +150,7 @@ impl Extension {
150150
let parent =
151151
client.block_header(&parent_hash.into()).expect("Parent header of the snapshot header must exist");
152152
return State::SnapshotBody {
153-
block: hash,
153+
header,
154154
prev_root: parent.transactions_root(),
155155
}
156156
}
@@ -414,8 +414,30 @@ impl NetworkExtension<Event> for Extension {
414414
}
415415
}
416416
State::SnapshotBody {
417+
ref header,
417418
..
418-
} => unimplemented!(),
419+
} => {
420+
for id in &peer_ids {
421+
if let Some(requests) = self.requests.get_mut(id) {
422+
ctrace!(SYNC, "Send snapshot body request to {}", id);
423+
let request = RequestMessage::Bodies(vec![header.hash()]);
424+
let request_id = self.last_request;
425+
self.last_request += 1;
426+
requests.push((request_id, request.clone()));
427+
self.api
428+
.send(id, Arc::new(Message::Request(request_id, request).rlp_bytes().into_vec()));
429+
430+
let token = &self.tokens[id];
431+
let token_info = self.tokens_info.get_mut(token).unwrap();
432+
433+
let _ = self.api.clear_timer(*token);
434+
self.api
435+
.set_timer_once(*token, Duration::from_millis(SYNC_EXPIRE_REQUEST_INTERVAL))
436+
.expect("Timer set succeeds");
437+
token_info.request_id = Some(request_id);
438+
}
439+
}
440+
}
419441
State::SnapshotChunk {
420442
block,
421443
ref mut restore,
@@ -811,20 +833,11 @@ impl Extension {
811833
match self.state {
812834
State::SnapshotHeader(hash, _) => match headers {
813835
[parent, header] if header.hash() == hash => {
814-
match self.client.import_bootstrap_header(&header) {
815-
Ok(_) | Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
816-
self.state = State::SnapshotBody {
817-
block: hash,
818-
prev_root: *parent.transactions_root(),
819-
};
820-
cdebug!(SYNC, "Transitioning state to {:?}", self.state);
821-
}
822-
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
823-
// FIXME: handle import errors
824-
Err(err) => {
825-
cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err);
826-
}
827-
}
836+
self.state = State::SnapshotBody {
837+
header: EncodedHeader::new(header.rlp_bytes().to_vec()),
838+
prev_root: *parent.transactions_root(),
839+
};
840+
cdebug!(SYNC, "Transitioning state to {:?}", self.state);
828841
}
829842
_ => cdebug!(
830843
SYNC,
@@ -883,42 +896,75 @@ impl Extension {
883896

884897
fn on_body_response(&mut self, hashes: Vec<BlockHash>, bodies: Vec<Vec<UnverifiedTransaction>>) {
885898
ctrace!(SYNC, "Received body response with lenth({}) {:?}", hashes.len(), hashes);
886-
{
887-
self.body_downloader.import_bodies(hashes, bodies);
888-
let completed = self.body_downloader.drain();
889-
for (hash, transactions) in completed {
890-
let header = self
891-
.client
892-
.block_header(&BlockId::Hash(hash))
893-
.expect("Downloaded body's header must exist")
894-
.decode();
895-
let block = Block {
896-
header,
897-
transactions,
898-
};
899-
cdebug!(SYNC, "Body download completed for #{}({})", block.header.number(), hash);
900-
match self.client.import_block(block.rlp_bytes(&Seal::With)) {
901-
Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
902-
cwarn!(SYNC, "Downloaded already existing block({})", hash)
903-
}
904-
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {
905-
cwarn!(SYNC, "Downloaded already queued in the verification queue({})", hash)
906-
}
907-
Err(err) => {
899+
900+
match self.state {
901+
State::SnapshotBody {
902+
ref header,
903+
prev_root,
904+
} => {
905+
let body = bodies.first().expect("Body response in SnapshotBody state has only one body");
906+
let new_root = skewed_merkle_root(prev_root, body.iter().map(Encodable::rlp_bytes));
907+
if header.transactions_root() == new_root {
908+
let block = Block {
909+
header: header.decode(),
910+
transactions: body.clone(),
911+
};
912+
match self.client.import_bootstrap_block(&block) {
913+
Ok(_) | Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
914+
self.state = State::SnapshotChunk {
915+
block: header.hash(),
916+
restore: SnapshotRestore::new(header.state_root()),
917+
};
918+
cdebug!(SYNC, "Transitioning state to {:?}", self.state);
919+
}
920+
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
908921
// FIXME: handle import errors
909-
cwarn!(SYNC, "Cannot import block({}): {:?}", hash, err);
910-
break
922+
Err(err) => {
923+
cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err);
924+
}
911925
}
912-
_ => {}
913926
}
914927
}
915-
}
928+
State::Full => {
929+
{
930+
self.body_downloader.import_bodies(hashes, bodies);
931+
let completed = self.body_downloader.drain();
932+
for (hash, transactions) in completed {
933+
let header = self
934+
.client
935+
.block_header(&BlockId::Hash(hash))
936+
.expect("Downloaded body's header must exist")
937+
.decode();
938+
let block = Block {
939+
header,
940+
transactions,
941+
};
942+
cdebug!(SYNC, "Body download completed for #{}({})", block.header.number(), hash);
943+
match self.client.import_block(block.rlp_bytes(&Seal::With)) {
944+
Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
945+
cwarn!(SYNC, "Downloaded already existing block({})", hash)
946+
}
947+
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {
948+
cwarn!(SYNC, "Downloaded already queued in the verification queue({})", hash)
949+
}
950+
Err(err) => {
951+
// FIXME: handle import errors
952+
cwarn!(SYNC, "Cannot import block({}): {:?}", hash, err);
953+
break
954+
}
955+
_ => {}
956+
}
957+
}
958+
}
916959

917-
let mut peer_ids: Vec<_> = self.header_downloaders.keys().cloned().collect();
918-
peer_ids.shuffle(&mut thread_rng());
960+
let mut peer_ids: Vec<_> = self.header_downloaders.keys().cloned().collect();
961+
peer_ids.shuffle(&mut thread_rng());
919962

920-
for id in peer_ids {
921-
self.send_body_request(&id);
963+
for id in peer_ids {
964+
self.send_body_request(&id);
965+
}
966+
}
967+
_ => {}
922968
}
923969
}
924970

0 commit comments

Comments
 (0)