Skip to content

Commit f4af598

Browse files
remagpieforiequal0
authored andcommitted
Make the snapshot header importable without parent
1 parent 403b519 commit f4af598

File tree

8 files changed

+99
-9
lines changed

8 files changed

+99
-9
lines changed

codechain/run_node.rs

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

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
@@ -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, ShardId, Tracker, TxHash};
30+
use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash};
3131
use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig};
3232
use hashdb::AsHashDB;
3333
use journaldb;
@@ -655,6 +655,15 @@ 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()) {
660+
return Err(BlockImportError::Import(ImportError::AlreadyInChain))
661+
}
662+
let import_lock = self.importer.import_lock.lock();
663+
self.importer.import_bootstrap_header(header, self, &import_lock);
664+
Ok(header.hash())
665+
}
666+
658667
fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult {
659668
let h = block.header().hash();
660669
let route = {

core/src/client/importer.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl Importer {
100100
}
101101

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

@@ -362,6 +362,23 @@ impl Importer {
362362
imported.len()
363363
}
364364

365+
pub fn import_bootstrap_header<'a>(&'a self, header: &'a Header, client: &Client, _importer_lock: &MutexGuard<()>) {
366+
let hash = header.hash();
367+
ctrace!(CLIENT, "Importing bootstrap header {}-{:?}", header.number(), hash);
368+
369+
{
370+
let chain = client.block_chain();
371+
let mut batch = DBTransaction::new();
372+
chain.insert_bootstrap_header(&mut batch, &HeaderView::new(&header.rlp_bytes()));
373+
client.db().write_buffered(batch);
374+
chain.commit();
375+
}
376+
377+
client.new_headers(&[hash], &[], &[hash], &[], &[], Some(hash));
378+
379+
client.db().flush().expect("DB flush failed.");
380+
}
381+
365382
fn check_header(&self, header: &Header, parent: &Header) -> bool {
366383
// FIXME: self.verifier.verify_block_family
367384
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};
@@ -201,6 +201,10 @@ pub trait ImportBlock {
201201
/// Import a header into the blockchain
202202
fn import_header(&self, bytes: Bytes) -> Result<BlockHash, BlockImportError>;
203203

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

core/src/client/test_client.rs

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

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

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() {
@@ -747,7 +749,7 @@ impl Extension {
747749
match self.state {
748750
State::SnapshotHeader(..) => {
749751
for header in headers {
750-
match self.client.import_header(header.rlp_bytes().to_vec()) {
752+
match self.client.import_bootstrap_header(&header) {
751753
Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {}
752754
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
753755
// FIXME: handle import errors

0 commit comments

Comments
 (0)