Skip to content

Commit bbbf439

Browse files
remagpieforiequal0
authored andcommitted
Update the best block after importing snapshot chunks
1 parent 1e76ebc commit bbbf439

File tree

7 files changed

+127
-37
lines changed

7 files changed

+127
-37
lines changed

core/src/blockchain/blockchain.rs

Lines changed: 20 additions & 9 deletions
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

Lines changed: 16 additions & 14 deletions
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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use cstate::{
2626
ActionHandler, AssetScheme, FindActionHandler, OwnedAsset, StateDB, StateResult, Text, TopLevelState, TopStateView,
2727
};
2828
use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken};
29+
use ctypes::header::Header;
2930
use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction};
3031
use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash};
3132
use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig};
@@ -655,15 +656,28 @@ impl ImportBlock for Client {
655656
Ok(self.importer.header_queue.import(unverified)?)
656657
}
657658

658-
fn import_bootstrap_block(&self, block: &Block) -> Result<BlockHash, BlockImportError> {
659+
fn import_trusted_header(&self, header: &Header) -> Result<BlockHash, BlockImportError> {
660+
if self.block_chain().is_known_header(&header.hash()) {
661+
return Err(BlockImportError::Import(ImportError::AlreadyInChain))
662+
}
663+
let import_lock = self.importer.import_lock.lock();
664+
self.importer.import_trusted_header(header, self, &import_lock);
665+
Ok(header.hash())
666+
}
667+
668+
fn import_trusted_block(&self, block: &Block) -> Result<BlockHash, BlockImportError> {
659669
if self.block_chain().is_known(&block.header.hash()) {
660670
return Err(BlockImportError::Import(ImportError::AlreadyInChain))
661671
}
662672
let import_lock = self.importer.import_lock.lock();
663-
self.importer.import_bootstrap_block(block, self, &import_lock);
673+
self.importer.import_trusted_block(block, self, &import_lock);
664674
Ok(block.header.hash())
665675
}
666676

677+
fn force_update_best_block(&self, hash: &BlockHash) {
678+
self.importer.force_update_best_block(hash, self)
679+
}
680+
667681
fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult {
668682
let h = block.header().hash();
669683
let route = {

core/src/client/importer.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -362,21 +362,47 @@ impl Importer {
362362
imported.len()
363363
}
364364

365-
pub fn import_bootstrap_block<'a>(&'a self, block: &'a Block, client: &Client, _importer_lock: &MutexGuard<()>) {
365+
pub fn import_trusted_header<'a>(&'a self, header: &'a Header, client: &Client, _importer_lock: &MutexGuard<()>) {
366+
let hash = header.hash();
367+
ctrace!(CLIENT, "Importing trusted header #{}-{:?}", header.number(), hash);
368+
369+
{
370+
let chain = client.block_chain();
371+
let mut batch = DBTransaction::new();
372+
chain.insert_floating_header(&mut batch, &HeaderView::new(&header.rlp_bytes()));
373+
client.db().write_buffered(batch);
374+
chain.commit();
375+
}
376+
client.new_headers(&[hash], &[], &[], &[], &[], None);
377+
378+
client.db().flush().expect("DB flush failed.");
379+
}
380+
381+
pub fn import_trusted_block<'a>(&'a self, block: &'a Block, client: &Client, importer_lock: &MutexGuard<()>) {
366382
let header = &block.header;
367383
let hash = header.hash();
368-
ctrace!(CLIENT, "Importing bootstrap block #{}-{:?}", header.number(), hash);
384+
ctrace!(CLIENT, "Importing trusted block #{}-{:?}", header.number(), hash);
369385

386+
self.import_trusted_header(header, client, importer_lock);
370387
{
371388
let chain = client.block_chain();
372389
let mut batch = DBTransaction::new();
373-
chain.insert_bootstrap_block(&mut batch, &block.rlp_bytes(&Seal::With));
390+
chain.insert_floating_block(&mut batch, &block.rlp_bytes(&Seal::With));
374391
client.db().write_buffered(batch);
375392
chain.commit();
376393
}
377-
client.new_headers(&[hash], &[], &[hash], &[], &[], Some(hash));
378-
self.miner.chain_new_blocks(client, &[hash], &[], &[hash], &[]);
379-
client.new_blocks(&[hash], &[], &[hash], &[], &[]);
394+
self.miner.chain_new_blocks(client, &[hash], &[], &[], &[]);
395+
client.new_blocks(&[hash], &[], &[], &[], &[]);
396+
397+
client.db().flush().expect("DB flush failed.");
398+
}
399+
400+
pub fn force_update_best_block(&self, hash: &BlockHash, client: &Client) {
401+
let chain = client.block_chain();
402+
let mut batch = DBTransaction::new();
403+
chain.force_update_best_block(&mut batch, hash);
404+
client.db().write_buffered(batch);
405+
chain.commit();
380406

381407
client.db().flush().expect("DB flush failed.");
382408
}

core/src/client/mod.rs

Lines changed: 11 additions & 3 deletions
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

Lines changed: 10 additions & 1 deletion
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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ impl NetworkExtension<Event> for Extension {
468468
self.send_chunk_request(&block, &root);
469469
} else {
470470
cdebug!(SYNC, "Transitioning state to {:?}", State::Full);
471+
self.client.force_update_best_block(&block);
471472
self.state = State::Full;
472473
}
473474
}
@@ -836,6 +837,24 @@ impl Extension {
836837
match self.state {
837838
State::SnapshotHeader(hash, _) => match headers {
838839
[parent, header] if header.hash() == hash => {
840+
match self.client.import_trusted_header(parent) {
841+
Ok(_)
842+
| Err(BlockImportError::Import(ImportError::AlreadyInChain))
843+
| Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
844+
Err(err) => {
845+
cwarn!(SYNC, "Cannot import header({}): {:?}", parent.hash(), err);
846+
return
847+
}
848+
}
849+
match self.client.import_trusted_header(header) {
850+
Ok(_)
851+
| Err(BlockImportError::Import(ImportError::AlreadyInChain))
852+
| Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
853+
Err(err) => {
854+
cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err);
855+
return
856+
}
857+
}
839858
self.state = State::SnapshotBody {
840859
header: EncodedHeader::new(header.rlp_bytes().to_vec()),
841860
prev_root: *parent.transactions_root(),
@@ -912,7 +931,7 @@ impl Extension {
912931
header: header.decode(),
913932
transactions: body.clone(),
914933
};
915-
match self.client.import_bootstrap_block(&block) {
934+
match self.client.import_trusted_block(&block) {
916935
Ok(_) | Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
917936
self.state = State::SnapshotChunk {
918937
block: header.hash(),
@@ -923,7 +942,7 @@ impl Extension {
923942
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
924943
// FIXME: handle import errors
925944
Err(err) => {
926-
cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err);
945+
cwarn!(SYNC, "Cannot import block({}): {:?}", header.hash(), err);
927946
}
928947
}
929948
}
@@ -1023,6 +1042,7 @@ impl Extension {
10231042
self.send_chunk_request(&block, &root);
10241043
} else {
10251044
cdebug!(SYNC, "Transitioning state to {:?}", State::Full);
1045+
self.client.force_update_best_block(&block);
10261046
self.state = State::Full;
10271047
}
10281048
}

0 commit comments

Comments
 (0)