Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions core/src/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,18 @@ impl BlockChain {
}
}

pub fn insert_bootstrap_header(&self, batch: &mut DBTransaction, header: &HeaderView) {
self.headerchain.insert_bootstrap_header(batch, header);

let hash = header.hash();

*self.pending_best_block_hash.write() = Some(hash);
batch.put(db::COL_EXTRA, BEST_BLOCK_KEY, &hash);

*self.pending_best_proposal_block_hash.write() = Some(hash);
batch.put(db::COL_EXTRA, BEST_PROPOSAL_BLOCK_KEY, &hash);
}

pub fn insert_header(
&self,
batch: &mut DBTransaction,
Expand Down
42 changes: 42 additions & 0 deletions core/src/blockchain/headerchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,48 @@ impl HeaderChain {
}
}

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

ctrace!(HEADERCHAIN, "Inserting bootstrap block header #{}({}) to the headerchain.", header.number(), hash);

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

assert!(self.pending_best_header_hash.read().is_none());
assert!(self.pending_best_proposal_block_hash.read().is_none());

let compressed_header = compress(header.rlp().as_raw(), blocks_swapper());
batch.put(db::COL_HEADERS, &hash, &compressed_header);

let mut new_hashes = HashMap::new();
new_hashes.insert(header.number(), hash);
let mut new_details = HashMap::new();
new_details.insert(hash, BlockDetails {
number: header.number(),
total_score: 0.into(),
parent: header.parent_hash(),
});

batch.put(db::COL_EXTRA, BEST_HEADER_KEY, &hash);
*self.pending_best_header_hash.write() = Some(hash);
batch.put(db::COL_EXTRA, BEST_PROPOSAL_HEADER_KEY, &hash);
*self.pending_best_proposal_block_hash.write() = Some(hash);

let mut pending_hashes = self.pending_hashes.write();
let mut pending_details = self.pending_details.write();

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

/// Inserts the header into backing cache database.
/// Expects the header to be valid and already verified.
/// If the header is already known, does nothing.
Expand Down
11 changes: 10 additions & 1 deletion core/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use cstate::{
};
use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken};
use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction};
use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash};
use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash};
use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig};
use kvdb::{DBTransaction, KeyValueDB};
use parking_lot::{Mutex, RwLock, RwLockReadGuard};
Expand Down Expand Up @@ -634,6 +634,15 @@ impl ImportBlock for Client {
Ok(self.importer.header_queue.import(unverified)?)
}

fn import_bootstrap_header(&self, header: &Header) -> Result<BlockHash, BlockImportError> {
if self.block_chain().is_known_header(&header.hash()) {
return Err(BlockImportError::Import(ImportError::AlreadyInChain))
}
let import_lock = self.importer.import_lock.lock();
self.importer.import_bootstrap_header(header, self, &import_lock);
Ok(header.hash())
}

fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult {
let h = block.header().hash();
let route = {
Expand Down
19 changes: 18 additions & 1 deletion core/src/client/importer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl Importer {
}

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

Expand Down Expand Up @@ -362,6 +362,23 @@ impl Importer {
imported.len()
}

pub fn import_bootstrap_header<'a>(&'a self, header: &'a Header, client: &Client, _importer_lock: &MutexGuard<()>) {
let hash = header.hash();
ctrace!(CLIENT, "Importing bootstrap header {}-{:?}", header.number(), hash);

{
let chain = client.block_chain();
let mut batch = DBTransaction::new();
chain.insert_bootstrap_header(&mut batch, &HeaderView::new(&header.rlp_bytes()));
client.db().write_buffered(batch);
chain.commit();
}

client.new_headers(&[hash], &[], &[hash], &[], &[], Some(hash));

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

fn check_header(&self, header: &Header, parent: &Header) -> bool {
// FIXME: self.verifier.verify_block_family
if let Err(e) = self.engine.verify_block_family(&header, &parent) {
Expand Down
6 changes: 5 additions & 1 deletion core/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use cmerkle::Result as TrieResult;
use cnetwork::NodeId;
use cstate::{AssetScheme, FindActionHandler, OwnedAsset, StateResult, Text, TopLevelState, TopStateView};
use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction};
use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash};
use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash};
use cvm::ChainTimeInfo;
use kvdb::KeyValueDB;
use primitives::{Bytes, H160, H256, U256};
Expand Down Expand Up @@ -196,6 +196,10 @@ pub trait ImportBlock {
/// Import a header into the blockchain
fn import_header(&self, bytes: Bytes) -> Result<BlockHash, BlockImportError>;

/// Import a trusted bootstrap header into the blockchain
/// Bootstrap headers don't execute any verifications
fn import_bootstrap_header(&self, bytes: &Header) -> Result<BlockHash, BlockImportError>;

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

Expand Down
4 changes: 4 additions & 0 deletions core/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,10 @@ impl ImportBlock for TestBlockChainClient {
unimplemented!()
}

fn import_bootstrap_header(&self, _header: &BlockHeader) -> Result<BlockHash, BlockImportError> {
unimplemented!()
}

fn import_sealed_block(&self, _block: &SealedBlock) -> ImportResult {
Ok(H256::default().into())
}
Expand Down
4 changes: 3 additions & 1 deletion core/src/consensus/tendermint/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ use crate::encoded;
use crate::error::{BlockError, Error};
use crate::snapshot_notify::NotifySender as SnapshotNotifySender;
use crate::transaction::{SignedTransaction, UnverifiedTransaction};
use crate::types::BlockStatus;
use crate::views::BlockView;
use crate::BlockId;
use std::cell::Cell;
Expand Down Expand Up @@ -965,7 +966,8 @@ impl Worker {
}

fn on_imported_proposal(&mut self, proposal: &Header) {
if proposal.number() < 1 {
// NOTE: Only the genesis block and the snapshot target don't have the parent in the blockchain
if self.client().block_status(&BlockId::Hash(*proposal.parent_hash())) == BlockStatus::Unknown {
return
}

Expand Down
15 changes: 15 additions & 0 deletions foundry/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use cidr::IpCidr;
use ckey::PlatformAddress;
use clap;
use cnetwork::{FilterEntry, NetworkConfig, SocketAddr};
use primitives::H256;
use toml;

pub use self::chain_type::ChainType;
Expand Down Expand Up @@ -257,6 +258,8 @@ pub struct Network {
pub min_peers: Option<usize>,
pub max_peers: Option<usize>,
pub sync: Option<bool>,
pub snapshot_hash: Option<H256>,
pub snapshot_number: Option<u64>,
pub transaction_relay: Option<bool>,
pub discovery: Option<bool>,
pub discovery_type: Option<String>,
Expand Down Expand Up @@ -540,6 +543,12 @@ impl Network {
if other.sync.is_some() {
self.sync = other.sync;
}
if other.snapshot_hash.is_some() {
self.snapshot_hash = other.snapshot_hash;
}
if other.snapshot_number.is_some() {
self.snapshot_number = other.snapshot_number;
}
if other.transaction_relay.is_some() {
self.transaction_relay = other.transaction_relay;
}
Expand Down Expand Up @@ -592,6 +601,12 @@ impl Network {
if matches.is_present("no-sync") {
self.sync = Some(false);
}
if let Some(snapshot_hash) = matches.value_of("snapshot-hash") {
self.snapshot_hash = Some(snapshot_hash.parse().map_err(|_| "Invalid snapshot-hash")?);
}
if let Some(snapshot_number) = matches.value_of("snapshot-number") {
self.snapshot_number = Some(snapshot_number.parse().map_err(|_| "Invalid snapshot-number")?);
}
if matches.is_present("no-tx-relay") {
self.transaction_relay = Some(false);
}
Expand Down
12 changes: 12 additions & 0 deletions foundry/foundry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,18 @@ args:
takes_value: true
conflicts_with:
- no-discovery
- snapshot-hash:
long: snapshot-hash
value_name: HASH
help: The block hash of the snapshot target block.
requires: snapshot-number
takes_value: true
- snapshot-number:
long: snapshot-number
value_name: NUM
help: The block number of the snapshot target block.
requires: snapshot-hash
takes_value: true
- no-snapshot:
long: no-snapshot
help: Disable snapshots
Expand Down
8 changes: 6 additions & 2 deletions foundry/run_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ pub fn run_node(matches: &ArgMatches<'_>) -> Result<(), String> {
let network_config = config.network_config()?;
// XXX: What should we do if the network id has been changed.
let c = client.client();
let network_id = c.common_params(BlockId::Latest).unwrap().network_id();
let network_id = c.common_params(BlockId::Number(0)).unwrap().network_id();
let routing_table = RoutingTable::new();
let service = network_start(network_id, timer_loop, &network_config, Arc::clone(&routing_table))?;

Expand All @@ -277,7 +277,11 @@ pub fn run_node(matches: &ArgMatches<'_>) -> Result<(), String> {
if config.network.sync.unwrap() {
let sync_sender = {
let client = client.client();
service.register_extension(move |api| BlockSyncExtension::new(client, api))
let snapshot_target = match (config.network.snapshot_hash, config.network.snapshot_number) {
(Some(hash), Some(num)) => Some((hash, num)),
_ => None,
};
service.register_extension(move |api| BlockSyncExtension::new(client, api, snapshot_target))
};
let sync = Arc::new(BlockSyncSender::from(sync_sender.clone()));
client.client().add_notify(Arc::downgrade(&sync) as Weak<dyn ChainNotify>);
Expand Down
Loading