Skip to content

Commit e7977ae

Browse files
remagpieforiequal0
authored andcommitted
Update the best block after importing snapshot chunks
1 parent 0ebd568 commit e7977ae

File tree

7 files changed

+127
-37
lines changed

7 files changed

+127
-37
lines changed

core/src/blockchain/blockchain.rs

+20-9
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@ impl BlockChain {
110110
}
111111
}
112112

113-
pub fn insert_bootstrap_block(&self, batch: &mut DBTransaction, bytes: &[u8]) {
113+
pub fn insert_floating_header(&self, batch: &mut DBTransaction, header: &HeaderView) {
114+
self.headerchain.insert_floating_header(batch, header);
115+
}
116+
117+
pub fn insert_floating_block(&self, batch: &mut DBTransaction, bytes: &[u8]) {
114118
let block = BlockView::new(bytes);
115119
let header = block.header_view();
116120
let hash = header.hash();
@@ -122,20 +126,27 @@ impl BlockChain {
122126
return
123127
}
124128

129+
self.insert_floating_header(batch, &header);
130+
self.body_db.insert_body(batch, &block);
131+
}
132+
133+
pub fn force_update_best_block(&self, batch: &mut DBTransaction, hash: &BlockHash) {
134+
ctrace!(BLOCKCHAIN, "Forcefully updating the best block to {}", hash);
135+
136+
assert!(self.is_known(hash));
125137
assert!(self.pending_best_block_hash.read().is_none());
126138
assert!(self.pending_best_proposal_block_hash.read().is_none());
127139

128-
self.headerchain.insert_bootstrap_header(batch, &header);
129-
self.body_db.insert_body(batch, &block);
140+
let block = self.block(hash).expect("Target block is known");
141+
self.headerchain.force_update_best_header(batch, hash);
130142
self.body_db.update_best_block(batch, &BestBlockChanged::CanonChainAppended {
131-
best_block: bytes.to_vec(),
143+
best_block: block.into_inner(),
132144
});
133145

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);
146+
batch.put(db::COL_EXTRA, BEST_BLOCK_KEY, hash);
147+
*self.pending_best_block_hash.write() = Some(*hash);
148+
batch.put(db::COL_EXTRA, BEST_PROPOSAL_BLOCK_KEY, hash);
149+
*self.pending_best_proposal_block_hash.write() = Some(*hash);
139150
}
140151

141152
/// Inserts the block into backing cache database.

core/src/blockchain/headerchain.rs

+16-14
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,19 @@ impl HeaderChain {
115115
}
116116
}
117117

118-
/// Inserts a bootstrap header into backing cache database.
119-
/// Makes the imported header the best header.
120-
/// Expects the header to be valid and already verified.
118+
/// Inserts a floating header into backing cache database.
119+
/// Expects the header to be valid.
121120
/// If the header is already known, does nothing.
122-
// FIXME: Find better return type. Returning `None` at duplication is not natural
123-
pub fn insert_bootstrap_header(&self, batch: &mut DBTransaction, header: &HeaderView) {
121+
pub fn insert_floating_header(&self, batch: &mut DBTransaction, header: &HeaderView) {
124122
let hash = header.hash();
125123

126-
ctrace!(HEADERCHAIN, "Inserting bootstrap block header #{}({}) to the headerchain.", header.number(), hash);
124+
ctrace!(HEADERCHAIN, "Inserting a floating block header #{}({}) to the headerchain.", header.number(), hash);
127125

128126
if self.is_known_header(&hash) {
129127
ctrace!(HEADERCHAIN, "Block header #{}({}) is already known.", header.number(), hash);
130128
return
131129
}
132130

133-
assert!(self.pending_best_header_hash.read().is_none());
134-
assert!(self.pending_best_proposal_block_hash.read().is_none());
135-
136131
let compressed_header = compress(header.rlp().as_raw(), blocks_swapper());
137132
batch.put(db::COL_HEADERS, &hash, &compressed_header);
138133

@@ -145,18 +140,25 @@ impl HeaderChain {
145140
parent: header.parent_hash(),
146141
});
147142

148-
batch.put(db::COL_EXTRA, BEST_HEADER_KEY, &hash);
149-
*self.pending_best_header_hash.write() = Some(hash);
150-
batch.put(db::COL_EXTRA, BEST_PROPOSAL_HEADER_KEY, &hash);
151-
*self.pending_best_proposal_block_hash.write() = Some(hash);
152-
153143
let mut pending_hashes = self.pending_hashes.write();
154144
let mut pending_details = self.pending_details.write();
155145

156146
batch.extend_with_cache(db::COL_EXTRA, &mut *pending_details, new_details, CacheUpdatePolicy::Overwrite);
157147
batch.extend_with_cache(db::COL_EXTRA, &mut *pending_hashes, new_hashes, CacheUpdatePolicy::Overwrite);
158148
}
159149

150+
pub fn force_update_best_header(&self, batch: &mut DBTransaction, hash: &BlockHash) {
151+
ctrace!(HEADERCHAIN, "Forcefully updating the best header to {}", hash);
152+
assert!(self.is_known_header(hash));
153+
assert!(self.pending_best_header_hash.read().is_none());
154+
assert!(self.pending_best_proposal_block_hash.read().is_none());
155+
156+
batch.put(db::COL_EXTRA, BEST_HEADER_KEY, hash);
157+
*self.pending_best_header_hash.write() = Some(*hash);
158+
batch.put(db::COL_EXTRA, BEST_PROPOSAL_HEADER_KEY, hash);
159+
*self.pending_best_proposal_block_hash.write() = Some(*hash);
160+
}
161+
160162
/// Inserts the header into backing cache database.
161163
/// Expects the header to be valid and already verified.
162164
/// If the header is already known, does nothing.

core/src/client/client.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use cstate::{
2727
ActionHandler, AssetScheme, FindActionHandler, OwnedAsset, StateDB, StateResult, Text, TopLevelState, TopStateView,
2828
};
2929
use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken};
30+
use ctypes::header::Header;
3031
use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction};
3132
use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash};
3233
use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig};
@@ -664,15 +665,28 @@ impl ImportBlock for Client {
664665
Ok(self.importer.header_queue.import(unverified)?)
665666
}
666667

667-
fn import_bootstrap_block(&self, block: &Block) -> Result<BlockHash, BlockImportError> {
668+
fn import_trusted_header(&self, header: &Header) -> Result<BlockHash, BlockImportError> {
669+
if self.block_chain().is_known_header(&header.hash()) {
670+
return Err(BlockImportError::Import(ImportError::AlreadyInChain))
671+
}
672+
let import_lock = self.importer.import_lock.lock();
673+
self.importer.import_trusted_header(header, self, &import_lock);
674+
Ok(header.hash())
675+
}
676+
677+
fn import_trusted_block(&self, block: &Block) -> Result<BlockHash, BlockImportError> {
668678
if self.block_chain().is_known(&block.header.hash()) {
669679
return Err(BlockImportError::Import(ImportError::AlreadyInChain))
670680
}
671681
let import_lock = self.importer.import_lock.lock();
672-
self.importer.import_bootstrap_block(block, self, &import_lock);
682+
self.importer.import_trusted_block(block, self, &import_lock);
673683
Ok(block.header.hash())
674684
}
675685

686+
fn force_update_best_block(&self, hash: &BlockHash) {
687+
self.importer.force_update_best_block(hash, self)
688+
}
689+
676690
fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult {
677691
let h = block.header().hash();
678692
let start = Instant::now();

core/src/client/importer.rs

+32-6
Original file line numberDiff line numberDiff line change
@@ -371,26 +371,52 @@ impl Importer {
371371
imported.len()
372372
}
373373

374-
pub fn import_bootstrap_block<'a>(&'a self, block: &'a Block, client: &Client, _importer_lock: &MutexGuard<()>) {
374+
pub fn import_trusted_header<'a>(&'a self, header: &'a Header, client: &Client, _importer_lock: &MutexGuard<()>) {
375+
let hash = header.hash();
376+
ctrace!(CLIENT, "Importing trusted header #{}-{:?}", header.number(), hash);
377+
378+
{
379+
let chain = client.block_chain();
380+
let mut batch = DBTransaction::new();
381+
chain.insert_floating_header(&mut batch, &HeaderView::new(&header.rlp_bytes()));
382+
client.db().write_buffered(batch);
383+
chain.commit();
384+
}
385+
client.new_headers(&[hash], &[], &[], &[], &[], 0, None);
386+
387+
client.db().flush().expect("DB flush failed.");
388+
}
389+
390+
pub fn import_trusted_block<'a>(&'a self, block: &'a Block, client: &Client, importer_lock: &MutexGuard<()>) {
375391
let header = &block.header;
376392
let hash = header.hash();
377-
ctrace!(CLIENT, "Importing bootstrap block #{}-{:?}", header.number(), hash);
393+
ctrace!(CLIENT, "Importing trusted block #{}-{:?}", header.number(), hash);
378394

395+
self.import_trusted_header(header, client, importer_lock);
379396
let start = Instant::now();
380397
{
381398
let chain = client.block_chain();
382399
let mut batch = DBTransaction::new();
383-
chain.insert_bootstrap_block(&mut batch, &block.rlp_bytes(&Seal::With));
400+
chain.insert_floating_block(&mut batch, &block.rlp_bytes(&Seal::With));
384401
client.db().write_buffered(batch);
385402
chain.commit();
386403
}
387404
let duration = {
388405
let elapsed = start.elapsed();
389406
elapsed.as_secs() * 1_000_000_000 + u64::from(elapsed.subsec_nanos())
390407
};
391-
client.new_headers(&[hash], &[], &[hash], &[], &[], 0, Some(hash));
392-
self.miner.chain_new_blocks(client, &[hash], &[], &[hash], &[]);
393-
client.new_blocks(&[hash], &[], &[hash], &[], &[], duration);
408+
self.miner.chain_new_blocks(client, &[hash], &[], &[], &[]);
409+
client.new_blocks(&[hash], &[], &[], &[], &[], duration);
410+
411+
client.db().flush().expect("DB flush failed.");
412+
}
413+
414+
pub fn force_update_best_block(&self, hash: &BlockHash, client: &Client) {
415+
let chain = client.block_chain();
416+
let mut batch = DBTransaction::new();
417+
chain.force_update_best_block(&mut batch, hash);
418+
client.db().write_buffered(batch);
419+
chain.commit();
394420

395421
client.db().flush().expect("DB flush failed.");
396422
}

core/src/client/mod.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use ckey::{Address, NetworkId, PlatformAddress, Public};
3737
use cmerkle::Result as TrieResult;
3838
use cnetwork::NodeId;
3939
use cstate::{AssetScheme, FindActionHandler, OwnedAsset, StateResult, Text, TopLevelState, TopStateView};
40+
use ctypes::header::Header;
4041
use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction};
4142
use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash};
4243
use cvm::ChainTimeInfo;
@@ -201,9 +202,16 @@ pub trait ImportBlock {
201202
/// Import a header into the blockchain
202203
fn import_header(&self, bytes: Bytes) -> Result<BlockHash, BlockImportError>;
203204

204-
/// Import a trusted bootstrap header into the blockchain
205-
/// Bootstrap headers don't execute any verifications
206-
fn import_bootstrap_block(&self, bytes: &Block) -> Result<BlockHash, BlockImportError>;
205+
/// Import a trusted header into the blockchain
206+
/// Trusted header doesn't go through any verifications and doesn't update the best header
207+
fn import_trusted_header(&self, header: &Header) -> Result<BlockHash, BlockImportError>;
208+
209+
/// Import a trusted block into the blockchain
210+
/// Trusted block doesn't go through any verifications and doesn't update the best block
211+
fn import_trusted_block(&self, block: &Block) -> Result<BlockHash, BlockImportError>;
212+
213+
/// Forcefully update the best block
214+
fn force_update_best_block(&self, hash: &BlockHash);
207215

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

core/src/client/test_client.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use cnetwork::NodeId;
4242
use cstate::tests::helpers::empty_top_state;
4343
use cstate::{FindActionHandler, StateDB, TopLevelState};
4444
use ctimer::{TimeoutHandler, TimerToken};
45+
use ctypes::header::Header;
4546
use ctypes::transaction::{Action, Transaction};
4647
use ctypes::{BlockHash, BlockNumber, CommonParams, Header as BlockHeader, Tracker, TxHash};
4748
use cvm::ChainTimeInfo;
@@ -510,7 +511,15 @@ impl ImportBlock for TestBlockChainClient {
510511
unimplemented!()
511512
}
512513

513-
fn import_bootstrap_block(&self, _header: &Block) -> Result<BlockHash, BlockImportError> {
514+
fn import_trusted_header(&self, _header: &Header) -> Result<BlockHash, BlockImportError> {
515+
unimplemented!()
516+
}
517+
518+
fn import_trusted_block(&self, _block: &Block) -> Result<BlockHash, BlockImportError> {
519+
unimplemented!()
520+
}
521+
522+
fn force_update_best_block(&self, _hash: &BlockHash) {
514523
unimplemented!()
515524
}
516525

sync/src/block/extension.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ impl NetworkExtension<Event> for Extension {
446446
self.send_chunk_request(&block, &root);
447447
} else {
448448
cdebug!(SYNC, "Transitioning state to {:?}", State::Full);
449+
self.client.force_update_best_block(&block);
449450
self.state = State::Full;
450451
}
451452
}
@@ -833,6 +834,24 @@ impl Extension {
833834
match self.state {
834835
State::SnapshotHeader(hash, _) => match headers {
835836
[parent, header] if header.hash() == hash => {
837+
match self.client.import_trusted_header(parent) {
838+
Ok(_)
839+
| Err(BlockImportError::Import(ImportError::AlreadyInChain))
840+
| Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
841+
Err(err) => {
842+
cwarn!(SYNC, "Cannot import header({}): {:?}", parent.hash(), err);
843+
return
844+
}
845+
}
846+
match self.client.import_trusted_header(header) {
847+
Ok(_)
848+
| Err(BlockImportError::Import(ImportError::AlreadyInChain))
849+
| Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
850+
Err(err) => {
851+
cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err);
852+
return
853+
}
854+
}
836855
self.state = State::SnapshotBody {
837856
header: EncodedHeader::new(header.rlp_bytes().to_vec()),
838857
prev_root: *parent.transactions_root(),
@@ -909,7 +928,7 @@ impl Extension {
909928
header: header.decode(),
910929
transactions: body.clone(),
911930
};
912-
match self.client.import_bootstrap_block(&block) {
931+
match self.client.import_trusted_block(&block) {
913932
Ok(_) | Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
914933
self.state = State::SnapshotChunk {
915934
block: header.hash(),
@@ -920,7 +939,7 @@ impl Extension {
920939
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
921940
// FIXME: handle import errors
922941
Err(err) => {
923-
cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err);
942+
cwarn!(SYNC, "Cannot import block({}): {:?}", header.hash(), err);
924943
}
925944
}
926945
}
@@ -1020,6 +1039,7 @@ impl Extension {
10201039
self.send_chunk_request(&block, &root);
10211040
} else {
10221041
cdebug!(SYNC, "Transitioning state to {:?}", State::Full);
1042+
self.client.force_update_best_block(&block);
10231043
self.state = State::Full;
10241044
}
10251045
}

0 commit comments

Comments
 (0)