Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Header-only sync for old forks #3942

Merged
merged 3 commits into from
Nov 5, 2019
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
43 changes: 27 additions & 16 deletions core/client/db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,12 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
inmem
}

/// Returns total numbet of blocks (headers) in the block DB.
#[cfg(feature = "test-helpers")]
pub fn blocks_count(&self) -> u64 {
self.blockchain.db.iter(columns::HEADER).count() as u64
}

/// Read (from storage or cache) changes trie config.
///
/// Currently changes tries configuration is set up once (at genesis) and could not
Expand Down Expand Up @@ -1121,7 +1127,7 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
);

transaction.put(columns::HEADER, &lookup_key, &pending_block.header.encode());
if let Some(body) = pending_block.body {
if let Some(body) = &pending_block.body {
transaction.put(columns::BODY, &lookup_key, &body.encode());
}
if let Some(justification) = pending_block.justification {
Expand All @@ -1133,21 +1139,26 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
transaction.put(columns::META, meta_keys::GENESIS_HASH, hash.as_ref());
}

let mut changeset: state_db::ChangeSet<Vec<u8>> = state_db::ChangeSet::default();
for (key, (val, rc)) in operation.db_updates.drain() {
if rc > 0 {
changeset.inserted.push((key, val.to_vec()));
} else if rc < 0 {
changeset.deleted.push(key);
let finalized = if pending_block.body.is_some() {
let mut changeset: state_db::ChangeSet<Vec<u8>> = state_db::ChangeSet::default();
for (key, (val, rc)) in operation.db_updates.drain() {
if rc > 0 {
changeset.inserted.push((key, val.to_vec()));
} else if rc < 0 {
changeset.deleted.push(key);
}
}
}
let number_u64 = number.saturated_into::<u64>();
let commit = self.storage.state_db.insert_block(&hash, number_u64, &pending_block.header.parent_hash(), changeset)
.map_err(|e: state_db::Error<io::Error>| client::error::Error::from(format!("State database error: {:?}", e)))?;
apply_state_commit(&mut transaction, commit);

// Check if need to finalize. Genesis is always finalized instantly.
let finalized = number_u64 == 0 || pending_block.leaf_state.is_final();
let number_u64 = number.saturated_into::<u64>();
let commit = self.storage.state_db.insert_block(&hash, number_u64, &pending_block.header.parent_hash(), changeset)
.map_err(|e: state_db::Error<io::Error>| client::error::Error::from(format!("State database error: {:?}", e)))?;
apply_state_commit(&mut transaction, commit);

// Check if need to finalize. Genesis is always finalized instantly.
let finalized = number_u64 == 0 || pending_block.leaf_state.is_final();
finalized
} else {
false
};

let header = &pending_block.header;
let is_best = pending_block.leaf_state.is_best();
Expand Down Expand Up @@ -1587,7 +1598,7 @@ mod tests {
};
let mut op = backend.begin_operation().unwrap();
backend.begin_state_operation(&mut op, block_id).unwrap();
op.set_block_data(header, None, None, NewBlockState::Best).unwrap();
op.set_block_data(header, Some(Vec::new()), None, NewBlockState::Best).unwrap();
op.update_changes_trie((changes_trie_update, ChangesTrieCacheAction::Clear)).unwrap();
backend.commit_operation(op).unwrap();

Expand Down
67 changes: 37 additions & 30 deletions core/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -936,22 +936,39 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
BlockOrigin::Genesis | BlockOrigin::NetworkInitialSync | BlockOrigin::File => false,
};

self.backend.begin_state_operation(&mut operation.op, BlockId::Hash(parent_hash))?;
let storage_changes = match &body {
Some(body) => {
self.backend.begin_state_operation(&mut operation.op, BlockId::Hash(parent_hash))?;

// ensure parent block is finalized to maintain invariant that
// finality is called sequentially.
if finalized {
self.apply_finality_with_block_hash(operation, parent_hash, None, info.best_hash, make_notifications)?;
}

// ensure parent block is finalized to maintain invariant that
// finality is called sequentially.
if finalized {
self.apply_finality_with_block_hash(operation, parent_hash, None, info.best_hash, make_notifications)?;
}
// FIXME #1232: correct path logic for when to execute this function
let (storage_update, changes_update, storage_changes) = self.block_execution(
&operation.op,
&import_headers,
origin,
hash,
&body,
)?;

// FIXME #1232: correct path logic for when to execute this function
let (storage_update, changes_update, storage_changes) = self.block_execution(
&operation.op,
&import_headers,
origin,
hash,
body.clone(),
)?;
operation.op.update_cache(new_cache);
if let Some(storage_update) = storage_update {
operation.op.update_db_storage(storage_update)?;
}
if let Some(storage_changes) = storage_changes.clone() {
operation.op.update_storage(storage_changes.0, storage_changes.1)?;
}
if let Some(Some(changes_update)) = changes_update {
operation.op.update_changes_trie(changes_update)?;
}
storage_changes
},
None => Default::default()
};

let is_new_best = finalized || match fork_choice {
ForkChoiceStrategy::LongestChain => import_headers.post().number() > &info.best_number,
Expand Down Expand Up @@ -986,17 +1003,6 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
leaf_state,
)?;

operation.op.update_cache(new_cache);
if let Some(storage_update) = storage_update {
operation.op.update_db_storage(storage_update)?;
}
if let Some(storage_changes) = storage_changes.clone() {
operation.op.update_storage(storage_changes.0, storage_changes.1)?;
}
if let Some(Some(changes_update)) = changes_update {
operation.op.update_changes_trie(changes_update)?;
}

operation.op.insert_aux(aux)?;

if make_notifications {
Expand All @@ -1023,7 +1029,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
import_headers: &PrePostHeader<Block::Header>,
origin: BlockOrigin,
hash: Block::Hash,
body: Option<Vec<Block::Extrinsic>>,
body: &[Block::Extrinsic],
) -> error::Result<(
Option<StorageUpdate<B, Block>>,
Option<Option<ChangesUpdate<Block>>>,
Expand Down Expand Up @@ -1061,7 +1067,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where

let encoded_block = <Block as BlockT>::encode_from(
import_headers.pre(),
&body.unwrap_or_default()
body,
);

let (_, storage_update, changes_update) = self.executor
Expand Down Expand Up @@ -1532,7 +1538,7 @@ impl<'a, B, E, Block, RA> consensus::BlockImport<Block> for &'a Client<B, E, Blo
&mut self,
block: BlockCheckParams<Block>,
) -> Result<ImportResult, Self::Error> {
let BlockCheckParams { hash, number, parent_hash } = block;
let BlockCheckParams { hash, number, parent_hash, header_only } = block;

if let Some(h) = self.fork_blocks.as_ref().and_then(|x| x.get(&number)) {
if &hash != h {
Expand All @@ -1550,7 +1556,9 @@ impl<'a, B, E, Block, RA> consensus::BlockImport<Block> for &'a Client<B, E, Blo
.map_err(|e| ConsensusError::ClientImport(e.to_string()))?
{
BlockStatus::InChainWithState | BlockStatus::Queued => {},
BlockStatus::Unknown | BlockStatus::InChainPruned => return Ok(ImportResult::UnknownParent),
BlockStatus::Unknown => return Ok(ImportResult::UnknownParent),
BlockStatus::InChainPruned if header_only => {},
BlockStatus::InChainPruned => return Ok(ImportResult::MissingState),
BlockStatus::KnownBad => return Ok(ImportResult::KnownBad),
}

Expand All @@ -1562,7 +1570,6 @@ impl<'a, B, E, Block, RA> consensus::BlockImport<Block> for &'a Client<B, E, Blo
BlockStatus::KnownBad => return Ok(ImportResult::KnownBad),
}


Ok(ImportResult::imported(false))
}
}
Expand Down
6 changes: 6 additions & 0 deletions core/consensus/common/src/block_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ pub enum ImportResult {
KnownBad,
/// Block parent is not in the chain.
UnknownParent,
/// Parent state is missing.
MissingState,
}

/// Auxiliary data associated with an imported block result.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ImportedAux {
/// Only the header has been imported. Block body verification was skipped.
pub header_only: bool,
/// Clear all pending justification requests.
pub clear_justification_requests: bool,
/// Request a justification for the given block.
Expand Down Expand Up @@ -98,6 +102,8 @@ pub struct BlockCheckParams<Block: BlockT> {
pub number: NumberFor<Block>,
/// Parent hash of the block that we verify.
pub parent_hash: Block::Hash,
/// Don't check state availability
pub header_only: bool,
}

/// Data required to import a Block.
Expand Down
11 changes: 10 additions & 1 deletion core/consensus/common/src/import_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ pub fn import_single_block<B: BlockT, V: Verifier<B>>(
Ok(BlockImportResult::ImportedKnown(number))
},
Ok(ImportResult::Imported(aux)) => Ok(BlockImportResult::ImportedUnknown(number, aux, peer.clone())),
Ok(ImportResult::MissingState) => {
debug!(target: "sync", "Parent state is missing for {}: {:?}, parent: {:?}", number, hash, parent_hash);
Err(BlockImportError::UnknownParent)
},
Ok(ImportResult::UnknownParent) => {
debug!(target: "sync", "Block with unknown parent {}: {:?}, parent: {:?}", number, hash, parent_hash);
Err(BlockImportError::UnknownParent)
Expand All @@ -217,7 +221,12 @@ pub fn import_single_block<B: BlockT, V: Verifier<B>>(
}
}
};
match import_error(import_handle.check_block(BlockCheckParams { hash, number, parent_hash }))? {
match import_error(import_handle.check_block(BlockCheckParams {
hash,
number,
parent_hash,
header_only: block.body.is_none(),
}))? {
BlockImportResult::ImportedUnknown { .. } => (),
r => return Ok(r), // Any other successful result means that the block is already imported.
}
Expand Down
4 changes: 4 additions & 0 deletions core/finality-grandpa/src/light_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ pub mod tests {
bad_justification: false,
needs_finality_proof: false,
is_new_best: true,
header_only: false,
}));
}

Expand All @@ -692,6 +693,7 @@ pub mod tests {
bad_justification: false,
needs_finality_proof: false,
is_new_best: true,
header_only: false,
}));
}

Expand All @@ -705,6 +707,7 @@ pub mod tests {
bad_justification: false,
needs_finality_proof: true,
is_new_best: true,
header_only: false,
}));
}

Expand All @@ -721,6 +724,7 @@ pub mod tests {
bad_justification: false,
needs_finality_proof: true,
is_new_best: false,
header_only: false,
},
));
}
Expand Down
1 change: 1 addition & 0 deletions core/finality-grandpa/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,7 @@ fn allows_reimporting_change_blocks() {
bad_justification: false,
needs_finality_proof: false,
is_new_best: true,
header_only: false,
}),
);

Expand Down
Loading