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

Commit 668eb63

Browse files
arkparchemetomakabkchr
authored andcommitted
Fast sync (#8884)
* State sync * Importing state fixes * Bugfixes * Sync with proof * Status reporting * Unsafe sync mode * Sync test * Cleanup * Apply suggestions from code review Co-authored-by: cheme <emericchevalier.pro@gmail.com> Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> * set_genesis_storage * Extract keys from range proof * Detect iter completion * Download and import bodies with fast sync * Replaced meta updates tuple with a struct * Fixed reverting finalized state * Reverted timeout * Typo * Doc * Doc * Fixed light client test * Fixed error handling * Tweaks * More UpdateMeta changes * Rename convert_transaction * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Code review suggestions * Fixed count handling Co-authored-by: cheme <emericchevalier.pro@gmail.com> Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
1 parent 631ceb4 commit 668eb63

File tree

54 files changed

+2120
-371
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2120
-371
lines changed

Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/api/src/backend.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use sp_consensus::BlockOrigin;
4141
use parking_lot::RwLock;
4242

4343
pub use sp_state_machine::Backend as StateBackend;
44+
pub use sp_consensus::ImportedState;
4445
use std::marker::PhantomData;
4546

4647
/// Extracts the state backend type for the given backend.
@@ -161,6 +162,10 @@ pub trait BlockImportOperation<Block: BlockT> {
161162
update: TransactionForSB<Self::State, Block>,
162163
) -> sp_blockchain::Result<()>;
163164

165+
/// Set genesis state. If `commit` is `false` the state is saved in memory, but is not written
166+
/// to the database.
167+
fn set_genesis_state(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash>;
168+
164169
/// Inject storage data into the database replacing any existing data.
165170
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash>;
166171

client/api/src/in_mem.rs

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,11 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
347347
genesis_hash: storage.genesis_hash,
348348
finalized_hash: storage.finalized_hash,
349349
finalized_number: storage.finalized_number,
350+
finalized_state: if storage.finalized_hash != Default::default() {
351+
Some((storage.finalized_hash.clone(), storage.finalized_number))
352+
} else {
353+
None
354+
},
350355
number_leaves: storage.leaves.count()
351356
}
352357
}
@@ -528,6 +533,32 @@ pub struct BlockImportOperation<Block: BlockT> {
528533
set_head: Option<BlockId<Block>>,
529534
}
530535

536+
impl<Block: BlockT> BlockImportOperation<Block> where
537+
Block::Hash: Ord,
538+
{
539+
fn apply_storage(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash> {
540+
check_genesis_storage(&storage)?;
541+
542+
let child_delta = storage.children_default.iter()
543+
.map(|(_storage_key, child_content)|
544+
(
545+
&child_content.child_info,
546+
child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref())))
547+
)
548+
);
549+
550+
let (root, transaction) = self.old_state.full_storage_root(
551+
storage.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
552+
child_delta,
553+
);
554+
555+
if commit {
556+
self.new_state = Some(transaction);
557+
}
558+
Ok(root)
559+
}
560+
}
561+
531562
impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperation<Block> where
532563
Block::Hash: Ord,
533564
{
@@ -569,24 +600,12 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
569600
Ok(())
570601
}
571602

572-
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash> {
573-
check_genesis_storage(&storage)?;
574-
575-
let child_delta = storage.children_default.iter()
576-
.map(|(_storage_key, child_content)|
577-
(
578-
&child_content.child_info,
579-
child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref())))
580-
)
581-
);
582-
583-
let (root, transaction) = self.old_state.full_storage_root(
584-
storage.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
585-
child_delta,
586-
);
603+
fn set_genesis_state(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash> {
604+
self.apply_storage(storage, commit)
605+
}
587606

588-
self.new_state = Some(transaction);
589-
Ok(root)
607+
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash> {
608+
self.apply_storage(storage, true)
590609
}
591610

592611
fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
@@ -806,12 +825,12 @@ impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block
806825
/// Check that genesis storage is valid.
807826
pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
808827
if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) {
809-
return Err(sp_blockchain::Error::GenesisInvalid.into());
828+
return Err(sp_blockchain::Error::InvalidState.into());
810829
}
811830

812831
if storage.children_default.keys()
813832
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key)) {
814-
return Err(sp_blockchain::Error::GenesisInvalid.into());
833+
return Err(sp_blockchain::Error::InvalidState.into());
815834
}
816835

817836
Ok(())

client/api/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub use proof_provider::*;
4141
pub use sp_blockchain::HeaderBackend;
4242

4343
pub use sp_state_machine::{StorageProof, ExecutionStrategy};
44+
pub use sp_storage::{StorageData, StorageKey, PrefixedStorageKey, ChildInfo};
4445

4546
/// Usage Information Provider interface
4647
///

client/api/src/proof_provider.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,31 @@ pub trait ProofProvider<Block: BlockT> {
7070
storage_key: Option<&PrefixedStorageKey>,
7171
key: &StorageKey,
7272
) -> sp_blockchain::Result<ChangesProof<Block::Header>>;
73+
74+
/// Given a `BlockId` iterate over all storage values starting at `start_key` exclusively,
75+
/// building proofs until size limit is reached. Returns combined proof and the number of collected keys.
76+
fn read_proof_collection(
77+
&self,
78+
id: &BlockId<Block>,
79+
start_key: &[u8],
80+
size_limit: usize,
81+
) -> sp_blockchain::Result<(StorageProof, u32)>;
82+
83+
/// Given a `BlockId` iterate over all storage values starting at `start_key`.
84+
/// Returns collected keys and values.
85+
fn storage_collection(
86+
&self,
87+
id: &BlockId<Block>,
88+
start_key: &[u8],
89+
size_limit: usize,
90+
) -> sp_blockchain::Result<Vec<(Vec<u8>, Vec<u8>)>>;
91+
92+
/// Verify read storage proof for a set of keys.
93+
/// Returns collected key-value pairs and a flag indicating if iteration is complete.
94+
fn verify_range_proof(
95+
&self,
96+
root: Block::Hash,
97+
proof: StorageProof,
98+
start_key: &[u8],
99+
) -> sp_blockchain::Result<(Vec<(Vec<u8>, Vec<u8>)>, bool)>;
73100
}

client/authority-discovery/src/worker/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ impl<Block: BlockT> HeaderBackend<Block> for TestApi {
6969
finalized_number: Zero::zero(),
7070
genesis_hash: Default::default(),
7171
number_leaves: Default::default(),
72+
finalized_state: None,
7273
}
7374
}
7475

client/cli/src/arg_enums.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,30 @@ arg_enum! {
232232
}
233233
}
234234

235+
arg_enum! {
236+
/// Syncing mode.
237+
#[allow(missing_docs)]
238+
#[derive(Debug, Clone, Copy)]
239+
pub enum SyncMode {
240+
// Full sync. Donwnload end verify all blocks.
241+
Full,
242+
// Download blocks without executing them. Download latest state with proofs.
243+
Fast,
244+
// Download blocks without executing them. Download latest state without proofs.
245+
FastUnsafe,
246+
}
247+
}
248+
249+
impl Into<sc_network::config::SyncMode> for SyncMode {
250+
fn into(self) -> sc_network::config::SyncMode {
251+
match self {
252+
SyncMode::Full => sc_network::config::SyncMode::Full,
253+
SyncMode::Fast => sc_network::config::SyncMode::Fast { skip_proofs: false },
254+
SyncMode::FastUnsafe => sc_network::config::SyncMode::Fast { skip_proofs: true },
255+
}
256+
}
257+
}
258+
235259
/// Default value for the `--execution-syncing` parameter.
236260
pub const DEFAULT_EXECUTION_SYNCING: ExecutionStrategy = ExecutionStrategy::NativeElseWasm;
237261
/// Default value for the `--execution-import-block` parameter.

client/cli/src/params/network_params.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1818

1919
use crate::params::node_key_params::NodeKeyParams;
20+
use crate::arg_enums::SyncMode;
2021
use sc_network::{
2122
config::{NetworkConfiguration, NodeKeyConfig, NonReservedPeerMode, SetConfig, TransportConfig},
2223
multiaddr::Protocol,
@@ -125,6 +126,13 @@ pub struct NetworkParams {
125126
/// Join the IPFS network and serve transactions over bitswap protocol.
126127
#[structopt(long)]
127128
pub ipfs_server: bool,
129+
130+
/// Blockchain syncing mode.
131+
/// Full - Download and validate full blockchain history (Default).
132+
/// Fast - Download blocks and the latest state only.
133+
/// FastUnsafe - Same as Fast, but do skips downloading state proofs.
134+
#[structopt(long, default_value = "Full")]
135+
pub sync: SyncMode,
128136
}
129137

130138
impl NetworkParams {
@@ -218,6 +226,7 @@ impl NetworkParams {
218226
kademlia_disjoint_query_paths: self.kademlia_disjoint_query_paths,
219227
yamux_window_size: None,
220228
ipfs_server: self.ipfs_server,
229+
sync_mode: self.sync.into(),
221230
}
222231
}
223232
}

client/consensus/aura/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use codec::{Encode, Decode, Codec};
4242

4343
use sp_consensus::{
4444
BlockImport, Environment, Proposer, CanAuthorWith, ForkChoiceStrategy, BlockImportParams,
45-
BlockOrigin, Error as ConsensusError, SelectChain,
45+
BlockOrigin, Error as ConsensusError, SelectChain, StateAction,
4646
};
4747
use sc_client_api::{backend::AuxStore, BlockOf, UsageProvider};
4848
use sp_blockchain::{Result as CResult, ProvideCache, HeaderBackend};
@@ -421,7 +421,9 @@ where
421421
let mut import_block = BlockImportParams::new(BlockOrigin::Own, header);
422422
import_block.post_digests.push(signature_digest_item);
423423
import_block.body = Some(body);
424-
import_block.storage_changes = Some(storage_changes);
424+
import_block.state_action = StateAction::ApplyChanges(
425+
sp_consensus::StorageChanges::Changes(storage_changes)
426+
);
425427
import_block.fork_choice = Some(ForkChoiceStrategy::LongestChain);
426428

427429
Ok(import_block)

client/consensus/babe/src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ use sp_consensus::{
101101
import_queue::{BasicQueue, CacheKeyId, DefaultImportQueue, Verifier},
102102
BlockCheckParams, BlockImport, BlockImportParams, BlockOrigin, Environment,
103103
Error as ConsensusError, ForkChoiceStrategy, Proposer, SelectChain, SlotData,
104+
StateAction,
104105
};
105106
use sp_consensus_babe::inherents::BabeInherentData;
106107
use sp_consensus_slots::Slot;
@@ -790,7 +791,9 @@ where
790791
let mut import_block = BlockImportParams::new(BlockOrigin::Own, header);
791792
import_block.post_digests.push(digest_item);
792793
import_block.body = Some(body);
793-
import_block.storage_changes = Some(storage_changes);
794+
import_block.state_action = StateAction::ApplyChanges(
795+
sp_consensus::StorageChanges::Changes(storage_changes)
796+
);
794797
import_block.intermediates.insert(
795798
Cow::from(INTERMEDIATE_KEY),
796799
Box::new(BabeIntermediate::<B> { epoch_descriptor }) as Box<_>,
@@ -1295,7 +1298,12 @@ impl<Block, Client, Inner> BlockImport<Block> for BabeBlockImport<Block, Client,
12951298
// early exit if block already in chain, otherwise the check for
12961299
// epoch changes will error when trying to re-import an epoch change
12971300
match self.client.status(BlockId::Hash(hash)) {
1298-
Ok(sp_blockchain::BlockStatus::InChain) => return Ok(ImportResult::AlreadyInChain),
1301+
Ok(sp_blockchain::BlockStatus::InChain) => {
1302+
// When re-importing existing block strip away intermediates.
1303+
let _ = block.take_intermediate::<BabeIntermediate<Block>>(INTERMEDIATE_KEY)?;
1304+
block.fork_choice = Some(ForkChoiceStrategy::Custom(false));
1305+
return self.inner.import_block(block, new_cache).await.map_err(Into::into)
1306+
},
12991307
Ok(sp_blockchain::BlockStatus::Unknown) => {},
13001308
Err(e) => return Err(ConsensusError::ClientImport(e.to_string())),
13011309
}

0 commit comments

Comments
 (0)