Skip to content

Commit abe60a3

Browse files
remagpieforiequal0
authored andcommitted
Import snapshot block with body
1 parent 0ba5323 commit abe60a3

File tree

6 files changed

+140
-77
lines changed

6 files changed

+140
-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
@@ -27,7 +27,7 @@ use cstate::{
2727
};
2828
use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken};
2929
use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction};
30-
use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash};
30+
use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash};
3131
use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig};
3232
use hashdb::AsHashDB;
3333
use journaldb;
@@ -42,7 +42,7 @@ use super::{
4242
ClientConfig, DatabaseClient, EngineClient, EngineInfo, Error as ClientError, ExecuteClient, ImportBlock,
4343
ImportResult, MiningBlockChainClient, Shard, StateInfo, StateOrBlock, TextClient,
4444
};
45-
use crate::block::{ClosedBlock, IsBlock, OpenBlock, SealedBlock};
45+
use crate::block::{Block, ClosedBlock, IsBlock, OpenBlock, SealedBlock};
4646
use crate::blockchain::{BlockChain, BlockProvider, BodyProvider, HeaderProvider, InvoiceProvider, TransactionAddress};
4747
use crate::client::{ConsensusClient, SnapshotClient, TermInfo};
4848
use crate::consensus::{CodeChainEngine, EngineError};
@@ -655,13 +655,13 @@ impl ImportBlock for Client {
655655
Ok(self.importer.header_queue.import(unverified)?)
656656
}
657657

658-
fn import_bootstrap_header(&self, header: &Header) -> Result<BlockHash, BlockImportError> {
659-
if self.block_chain().is_known_header(&header.hash()) {
658+
fn import_bootstrap_block(&self, block: &Block) -> Result<BlockHash, BlockImportError> {
659+
if self.block_chain().is_known(&block.header.hash()) {
660660
return Err(BlockImportError::Import(ImportError::AlreadyInChain))
661661
}
662662
let import_lock = self.importer.import_lock.lock();
663-
self.importer.import_bootstrap_header(header, self, &import_lock);
664-
Ok(header.hash())
663+
self.importer.import_bootstrap_block(block, self, &import_lock);
664+
Ok(block.header.hash())
665665
}
666666

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

core/src/client/importer.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ use std::collections::{HashMap, HashSet};
1919
use std::sync::Arc;
2020

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

2828
use super::{BlockChainTrait, Client, ClientConfig};
29-
use crate::block::{enact, IsBlock, LockedBlock};
29+
use crate::block::{enact, Block, IsBlock, LockedBlock};
3030
use crate::blockchain::{BodyProvider, HeaderProvider, ImportRoute};
3131
use crate::client::EngineInfo;
3232
use crate::consensus::CodeChainEngine;
@@ -362,19 +362,21 @@ impl Importer {
362362
imported.len()
363363
}
364364

365-
pub fn import_bootstrap_header<'a>(&'a self, header: &'a Header, client: &Client, _importer_lock: &MutexGuard<()>) {
365+
pub fn import_bootstrap_block<'a>(&'a self, block: &'a Block, client: &Client, _importer_lock: &MutexGuard<()>) {
366+
let header = &block.header;
366367
let hash = header.hash();
367-
ctrace!(CLIENT, "Importing bootstrap header {}-{:?}", header.number(), hash);
368+
ctrace!(CLIENT, "Importing bootstrap block #{}-{:?}", header.number(), hash);
368369

369370
{
370371
let chain = client.block_chain();
371372
let mut batch = DBTransaction::new();
372-
chain.insert_bootstrap_header(&mut batch, &HeaderView::new(&header.rlp_bytes()));
373+
chain.insert_bootstrap_block(&mut batch, &block.rlp_bytes(&Seal::With));
373374
client.db().write_buffered(batch);
374375
chain.commit();
375376
}
376-
377377
client.new_headers(&[hash], &[], &[hash], &[], &[], Some(hash));
378+
self.miner.chain_new_blocks(client, &[hash], &[], &[hash], &[]);
379+
client.new_blocks(&[hash], &[], &[hash], &[], &[]);
378380

379381
client.db().flush().expect("DB flush failed.");
380382
}

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
}
@@ -437,8 +437,29 @@ impl NetworkExtension<Event> for Extension {
437437
}
438438
}
439439
State::SnapshotBody {
440+
ref header,
440441
..
441-
} => unimplemented!(),
442+
} => {
443+
for id in &peer_ids {
444+
if let Some(requests) = self.requests.get_mut(id) {
445+
ctrace!(SYNC, "Send snapshot body request to {}", id);
446+
let request = RequestMessage::Bodies(vec![header.hash()]);
447+
let request_id = self.last_request;
448+
self.last_request += 1;
449+
requests.push((request_id, request.clone()));
450+
self.api.send(id, Arc::new(Message::Request(request_id, request).rlp_bytes()));
451+
452+
let token = &self.tokens[id];
453+
let token_info = self.tokens_info.get_mut(token).unwrap();
454+
455+
let _ = self.api.clear_timer(*token);
456+
self.api
457+
.set_timer_once(*token, Duration::from_millis(SYNC_EXPIRE_REQUEST_INTERVAL))
458+
.expect("Timer set succeeds");
459+
token_info.request_id = Some(request_id);
460+
}
461+
}
462+
}
442463
State::SnapshotChunk {
443464
block,
444465
ref mut restore,
@@ -815,20 +836,11 @@ impl Extension {
815836
match self.state {
816837
State::SnapshotHeader(hash, _) => match headers {
817838
[parent, header] if header.hash() == hash => {
818-
match self.client.import_bootstrap_header(&header) {
819-
Ok(_) | Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
820-
self.state = State::SnapshotBody {
821-
block: hash,
822-
prev_root: *parent.transactions_root(),
823-
};
824-
cdebug!(SYNC, "Transitioning state to {:?}", self.state);
825-
}
826-
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
827-
// FIXME: handle import errors
828-
Err(err) => {
829-
cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err);
830-
}
831-
}
839+
self.state = State::SnapshotBody {
840+
header: EncodedHeader::new(header.rlp_bytes().to_vec()),
841+
prev_root: *parent.transactions_root(),
842+
};
843+
cdebug!(SYNC, "Transitioning state to {:?}", self.state);
832844
}
833845
_ => cdebug!(
834846
SYNC,
@@ -887,42 +899,75 @@ impl Extension {
887899

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

921-
let mut peer_ids: Vec<_> = self.header_downloaders.keys().cloned().collect();
922-
peer_ids.shuffle(&mut thread_rng());
963+
let mut peer_ids: Vec<_> = self.header_downloaders.keys().cloned().collect();
964+
peer_ids.shuffle(&mut thread_rng());
923965

924-
for id in peer_ids {
925-
self.send_body_request(&id);
966+
for id in peer_ids {
967+
self.send_body_request(&id);
968+
}
969+
}
970+
_ => {}
926971
}
927972
}
928973

0 commit comments

Comments
 (0)