Skip to content

Commit 1cefe89

Browse files
remagpieforiequal0
authored andcommitted
Update the best block after importing snapshot chunks
1 parent 476afaa commit 1cefe89

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;
@@ -202,9 +203,16 @@ pub trait ImportBlock {
202203
/// Import a header into the blockchain
203204
fn import_header(&self, bytes: Bytes) -> Result<BlockHash, BlockImportError>;
204205

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

209217
/// Import sealed block. Skips all verifications.
210218
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;
@@ -509,7 +510,15 @@ impl ImportBlock for TestBlockChainClient {
509510
unimplemented!()
510511
}
511512

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

sync/src/block/extension.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ impl NetworkExtension<Event> for Extension {
445445
self.send_chunk_request(&block, &root);
446446
} else {
447447
cdebug!(SYNC, "Transitioning state to {:?}", State::Full);
448+
self.client.force_update_best_block(&block);
448449
self.state = State::Full;
449450
}
450451
}
@@ -832,6 +833,24 @@ impl Extension {
832833
match self.state {
833834
State::SnapshotHeader(hash, _) => match headers {
834835
[parent, header] if header.hash() == hash => {
836+
match self.client.import_trusted_header(parent) {
837+
Ok(_)
838+
| Err(BlockImportError::Import(ImportError::AlreadyInChain))
839+
| Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
840+
Err(err) => {
841+
cwarn!(SYNC, "Cannot import header({}): {:?}", parent.hash(), err);
842+
return
843+
}
844+
}
845+
match self.client.import_trusted_header(header) {
846+
Ok(_)
847+
| Err(BlockImportError::Import(ImportError::AlreadyInChain))
848+
| Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
849+
Err(err) => {
850+
cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err);
851+
return
852+
}
853+
}
835854
self.state = State::SnapshotBody {
836855
header: EncodedHeader::new(header.rlp_bytes().to_vec()),
837856
prev_root: *parent.transactions_root(),
@@ -908,7 +927,7 @@ impl Extension {
908927
header: header.decode(),
909928
transactions: body.clone(),
910929
};
911-
match self.client.import_bootstrap_block(&block) {
930+
match self.client.import_trusted_block(&block) {
912931
Ok(_) | Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
913932
self.state = State::SnapshotChunk {
914933
block: header.hash(),
@@ -919,7 +938,7 @@ impl Extension {
919938
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
920939
// FIXME: handle import errors
921940
Err(err) => {
922-
cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err);
941+
cwarn!(SYNC, "Cannot import block({}): {:?}", header.hash(), err);
923942
}
924943
}
925944
}
@@ -1019,6 +1038,7 @@ impl Extension {
10191038
self.send_chunk_request(&block, &root);
10201039
} else {
10211040
cdebug!(SYNC, "Transitioning state to {:?}", State::Full);
1041+
self.client.force_update_best_block(&block);
10221042
self.state = State::Full;
10231043
}
10241044
}

0 commit comments

Comments
 (0)