Skip to content

Commit ea56c0e

Browse files
committed
Make the snapshot header importable without parent
1 parent 355f4d1 commit ea56c0e

File tree

8 files changed

+100
-9
lines changed

8 files changed

+100
-9
lines changed

codechain/run_node.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ pub fn run_node(matches: &ArgMatches) -> Result<(), String> {
287287
let network_config = config.network_config()?;
288288
// XXX: What should we do if the network id has been changed.
289289
let c = client.client();
290-
let network_id = c.common_params(BlockId::Latest).unwrap().network_id();
290+
let network_id = c.common_params(BlockId::Number(0)).unwrap().network_id();
291291
let routing_table = RoutingTable::new();
292292
let service = network_start(network_id, timer_loop, &network_config, Arc::clone(&routing_table))?;
293293

core/src/blockchain/blockchain.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ 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+
101113
pub fn insert_header(
102114
&self,
103115
batch: &mut DBTransaction,

core/src/blockchain/headerchain.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,48 @@ 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.
121+
/// 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) {
124+
let hash = header.hash();
125+
126+
ctrace!(HEADERCHAIN, "Inserting bootstrap block header #{}({}) to the headerchain.", header.number(), hash);
127+
128+
if self.is_known_header(&hash) {
129+
ctrace!(HEADERCHAIN, "Block header #{}({}) is already known.", header.number(), hash);
130+
return
131+
}
132+
133+
assert!(self.pending_best_header_hash.read().is_none());
134+
assert!(self.pending_best_proposal_block_hash.read().is_none());
135+
136+
let compressed_header = compress(header.rlp().as_raw(), blocks_swapper());
137+
batch.put(db::COL_HEADERS, &hash, &compressed_header);
138+
139+
let mut new_hashes = HashMap::new();
140+
new_hashes.insert(header.number(), hash);
141+
let mut new_details = HashMap::new();
142+
new_details.insert(hash, BlockDetails {
143+
number: header.number(),
144+
total_score: 0.into(),
145+
parent: header.parent_hash(),
146+
});
147+
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+
153+
let mut pending_hashes = self.pending_hashes.write();
154+
let mut pending_details = self.pending_details.write();
155+
156+
batch.extend_with_cache(db::COL_EXTRA, &mut *pending_details, new_details, CacheUpdatePolicy::Overwrite);
157+
batch.extend_with_cache(db::COL_EXTRA, &mut *pending_hashes, new_hashes, CacheUpdatePolicy::Overwrite);
158+
}
159+
118160
/// Inserts the header into backing cache database.
119161
/// Expects the header to be valid and already verified.
120162
/// If the header is already known, does nothing.

core/src/client/client.rs

Lines changed: 10 additions & 1 deletion
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, ShardId, Tracker, TxHash};
31+
use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash};
3232
use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig};
3333
use hashdb::AsHashDB;
3434
use journaldb;
@@ -664,6 +664,15 @@ 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()) {
669+
return Err(BlockImportError::Import(ImportError::AlreadyInChain))
670+
}
671+
let import_lock = self.importer.import_lock.lock();
672+
self.importer.import_bootstrap_header(header, self, &import_lock);
673+
Ok(header.hash())
674+
}
675+
667676
fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult {
668677
let h = block.header().hash();
669678
let start = Instant::now();

core/src/client/importer.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,13 @@ impl Importer {
101101
}
102102

103103
{
104-
let headers: Vec<&Header> = blocks.iter().map(|block| &block.header).collect();
104+
let headers: Vec<_> = blocks.iter().map(|block| &block.header).collect();
105105
self.import_headers(headers, client, &import_lock);
106106
}
107107

108108
let start = Instant::now();
109109

110+
// NOTE: There are no situation importing "trusted block"s.
110111
for block in blocks {
111112
let header = &block.header;
112113
ctrace!(CLIENT, "Importing block {}", header.number());
@@ -370,6 +371,23 @@ impl Importer {
370371
imported.len()
371372
}
372373

374+
pub fn import_bootstrap_header<'a>(&'a self, header: &'a Header, client: &Client, _importer_lock: &MutexGuard<()>) {
375+
let hash = header.hash();
376+
ctrace!(CLIENT, "Importing bootstrap header {}-{:?}", header.number(), hash);
377+
378+
{
379+
let chain = client.block_chain();
380+
let mut batch = DBTransaction::new();
381+
chain.insert_bootstrap_header(&mut batch, &HeaderView::new(&header.rlp_bytes()));
382+
client.db().write_buffered(batch);
383+
chain.commit();
384+
}
385+
386+
client.new_headers(&[hash], &[], &[hash], &[], &[], 0, Some(hash));
387+
388+
client.db().flush().expect("DB flush failed.");
389+
}
390+
373391
fn check_header(&self, header: &Header, parent: &Header) -> bool {
374392
// FIXME: self.verifier.verify_block_family
375393
if let Err(e) = self.engine.verify_block_family(&header, &parent) {

core/src/client/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use cmerkle::Result as TrieResult;
3737
use cnetwork::NodeId;
3838
use cstate::{AssetScheme, FindActionHandler, OwnedAsset, StateResult, Text, TopLevelState, TopStateView};
3939
use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction};
40-
use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash};
40+
use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash};
4141
use cvm::ChainTimeInfo;
4242
use kvdb::KeyValueDB;
4343
use primitives::{Bytes, H160, H256, U256};
@@ -200,6 +200,10 @@ pub trait ImportBlock {
200200
/// Import a header into the blockchain
201201
fn import_header(&self, bytes: Bytes) -> Result<BlockHash, BlockImportError>;
202202

203+
/// Import a trusted bootstrap header into the blockchain
204+
/// Bootstrap headers don't execute any verifications
205+
fn import_bootstrap_header(&self, bytes: &Header) -> Result<BlockHash, BlockImportError>;
206+
203207
/// Import sealed block. Skips all verifications.
204208
fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult;
205209

core/src/client/test_client.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,10 @@ impl ImportBlock for TestBlockChainClient {
510510
unimplemented!()
511511
}
512512

513+
fn import_bootstrap_header(&self, _header: &BlockHeader) -> Result<BlockHash, BlockImportError> {
514+
unimplemented!()
515+
}
516+
513517
fn import_sealed_block(&self, _block: &SealedBlock) -> ImportResult {
514518
Ok(H256::default().into())
515519
}

sync/src/block/extension.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,12 @@ impl Extension {
9999
let mut header = client.best_header();
100100
let mut hollow_headers = vec![header.decode()];
101101
while client.block_body(&BlockId::Hash(header.hash())).is_none() {
102-
header = client
103-
.block_header(&BlockId::Hash(header.parent_hash()))
104-
.expect("Every imported header must have parent");
105-
hollow_headers.push(header.decode());
102+
if let Some(h) = client.block_header(&BlockId::Hash(header.parent_hash())) {
103+
header = h;
104+
hollow_headers.push(header.decode());
105+
} else {
106+
break
107+
}
106108
}
107109
let mut body_downloader = BodyDownloader::default();
108110
for neighbors in hollow_headers.windows(2).rev() {
@@ -743,7 +745,7 @@ impl Extension {
743745
match self.state {
744746
State::SnapshotHeader(..) => {
745747
for header in headers {
746-
match self.client.import_header(header.rlp_bytes().to_vec()) {
748+
match self.client.import_bootstrap_header(&header) {
747749
Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {}
748750
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
749751
// FIXME: handle import errors

0 commit comments

Comments
 (0)