Skip to content

Commit 476afaa

Browse files
remagpieforiequal0
authored andcommitted
Import snapshot block with body
1 parent ad41c34 commit 476afaa

File tree

6 files changed

+145
-77
lines changed

6 files changed

+145
-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::client::EngineInfo;
3333
use crate::consensus::CodeChainEngine;
@@ -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;
@@ -204,7 +204,7 @@ pub trait ImportBlock {
204204

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

209209
/// Import sealed block. Skips all verifications.
210210
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::{
5858
AccountData, BlockChainClient, BlockChainTrait, BlockProducer, BlockStatus, ConsensusClient, EngineInfo,
@@ -509,7 +509,7 @@ impl ImportBlock for TestBlockChainClient {
509509
unimplemented!()
510510
}
511511

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

sync/src/block/extension.rs

Lines changed: 93 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 {
@@ -151,7 +151,7 @@ impl Extension {
151151
let parent =
152152
client.block_header(&parent_hash.into()).expect("Parent header of the snapshot header must exist");
153153
return State::SnapshotBody {
154-
block: hash,
154+
header,
155155
prev_root: parent.transactions_root(),
156156
}
157157
}
@@ -414,8 +414,29 @@ 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.send(id, Arc::new(Message::Request(request_id, request).rlp_bytes()));
428+
429+
let token = &self.tokens[id];
430+
let token_info = self.tokens_info.get_mut(token).unwrap();
431+
432+
let _ = self.api.clear_timer(*token);
433+
self.api
434+
.set_timer_once(*token, Duration::from_millis(SYNC_EXPIRE_REQUEST_INTERVAL))
435+
.expect("Timer set succeeds");
436+
token_info.request_id = Some(request_id);
437+
}
438+
}
439+
}
419440
State::SnapshotChunk {
420441
block,
421442
ref mut restore,
@@ -811,20 +832,11 @@ impl Extension {
811832
match self.state {
812833
State::SnapshotHeader(hash, _) => match headers {
813834
[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-
}
835+
self.state = State::SnapshotBody {
836+
header: EncodedHeader::new(header.rlp_bytes().to_vec()),
837+
prev_root: *parent.transactions_root(),
838+
};
839+
cdebug!(SYNC, "Transitioning state to {:?}", self.state);
828840
}
829841
_ => cdebug!(
830842
SYNC,
@@ -883,42 +895,75 @@ impl Extension {
883895

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

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

920-
for id in peer_ids {
921-
self.send_body_request(&id);
962+
for id in peer_ids {
963+
self.send_body_request(&id);
964+
}
965+
}
966+
_ => {}
922967
}
923968
}
924969

0 commit comments

Comments
 (0)