Skip to content

Commit 402b5ac

Browse files
author
Andronik Ordian
committed
Generalize SnapshotService implementation
1 parent da7c0f6 commit 402b5ac

File tree

5 files changed

+118
-53
lines changed

5 files changed

+118
-53
lines changed

ethcore/service/src/service.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ use stop_guard::StopGuard;
2828
use sync::PrivateTxHandler;
2929
use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage};
3030
use ethcore::miner::Miner;
31-
use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams};
31+
use ethcore::snapshot::service::{
32+
Service as SnapshotService,
33+
ServiceParams as SnapServiceParams,
34+
FullNodeRestorationParams
35+
};
3236
use ethcore::snapshot::{SnapshotService as _SnapshotService, RestorationStatus};
3337
use ethcore::spec::Spec;
3438
use ethcore::account_provider::AccountProvider;
@@ -67,7 +71,7 @@ impl PrivateTxHandler for PrivateTxService {
6771
pub struct ClientService {
6872
io_service: Arc<IoService<ClientIoMessage>>,
6973
client: Arc<Client>,
70-
snapshot: Arc<SnapshotService>,
74+
snapshot: Arc<SnapshotService<FullNodeRestorationParams>>,
7175
private_tx: Arc<PrivateTxService>,
7276
database: Arc<KeyValueDB>,
7377
_stop_guard: StopGuard,
@@ -97,9 +101,11 @@ impl ClientService {
97101

98102
let snapshot_params = SnapServiceParams {
99103
engine: spec.engine.clone(),
100-
genesis_block: spec.genesis_block(),
101104
restoration_db_handler: restoration_db_handler,
102-
pruning: pruning,
105+
chain_params: FullNodeRestorationParams {
106+
pruning,
107+
genesis_block: spec.genesis_block(),
108+
},
103109
channel: io_service.channel(),
104110
snapshot_root: snapshot_path.into(),
105111
db_restore: client.clone(),
@@ -147,7 +153,7 @@ impl ClientService {
147153
}
148154

149155
/// Get snapshot interface.
150-
pub fn snapshot_service(&self) -> Arc<SnapshotService> {
156+
pub fn snapshot_service(&self) -> Arc<SnapshotService<FullNodeRestorationParams>> {
151157
self.snapshot.clone()
152158
}
153159

@@ -178,7 +184,7 @@ impl ClientService {
178184
/// IO interface for the Client handler
179185
struct ClientIoHandler {
180186
client: Arc<Client>,
181-
snapshot: Arc<SnapshotService>,
187+
snapshot: Arc<SnapshotService<FullNodeRestorationParams>>,
182188
}
183189

184190
const CLIENT_TICK_TIMER: TimerToken = 0;

ethcore/src/client/client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,9 +1279,9 @@ impl Client {
12791279
}
12801280
}
12811281

1282-
impl snapshot::DatabaseRestore for Client {
1282+
impl snapshot::DatabaseRestore<snapshot::FullNodeRestorationParams> for Client {
12831283
/// Restart the client with a new backend
1284-
fn restore_db(&self, new_db: &str) -> Result<(), EthcoreError> {
1284+
fn restore_db(&self, new_db: &str, _: &snapshot::FullNodeRestorationParams) -> Result<(), EthcoreError> {
12851285
trace!(target: "snapshot", "Replacing client database with {:?}", new_db);
12861286

12871287
let _import_lock = self.importer.import_lock.lock();

ethcore/src/snapshot/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use rand::{Rng, OsRng};
5353
pub use self::error::Error;
5454

5555
pub use self::consensus::*;
56-
pub use self::service::{Service, DatabaseRestore};
56+
pub use self::service::{Service, DatabaseRestore, FullNodeRestorationParams};
5757
pub use self::traits::SnapshotService;
5858
pub use self::watcher::Watcher;
5959
pub use types::snapshot_manifest::ManifestData;

ethcore/src/snapshot/service.rs

Lines changed: 97 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,18 @@ impl Drop for Guard {
6666
}
6767

6868
/// External database restoration handler
69-
pub trait DatabaseRestore: Send + Sync {
69+
pub trait DatabaseRestore<T: ChainRestorationParams>: Send + Sync {
7070
/// Restart with a new backend. Takes ownership of passed database and moves it to a new location.
71-
fn restore_db(&self, new_db: &str) -> Result<(), Error>;
71+
fn restore_db(&self, new_db: &str, params: &T) -> Result<(), Error>;
7272
}
7373

7474
/// State restoration manager.
75-
struct Restoration {
75+
pub struct Restoration {
7676
manifest: ManifestData,
7777
state_chunks_left: HashSet<H256>,
7878
block_chunks_left: HashSet<H256>,
79-
state: StateRebuilder,
79+
// TODO: maybe a more type-safe API?
80+
state: Option<StateRebuilder>,
8081
secondary: Box<Rebuilder>,
8182
writer: Option<LooseWriter>,
8283
snappy_buffer: Bytes,
@@ -118,7 +119,7 @@ impl Restoration {
118119
manifest: manifest,
119120
state_chunks_left: state_chunks,
120121
block_chunks_left: block_chunks,
121-
state: StateRebuilder::new(raw_db.clone(), params.pruning),
122+
state: Some(StateRebuilder::new(raw_db.clone(), params.pruning)),
122123
secondary: secondary,
123124
writer: params.writer,
124125
snappy_buffer: Vec::new(),
@@ -130,6 +131,10 @@ impl Restoration {
130131

131132
// feeds a state chunk, aborts early if `flag` becomes false.
132133
fn feed_state(&mut self, hash: H256, chunk: &[u8], flag: &AtomicBool) -> Result<(), Error> {
134+
if self.state.is_none() {
135+
trace!(target: "snapshot", "Feeding a chunk state to a light client");
136+
return Ok(());
137+
}
133138
if self.state_chunks_left.contains(&hash) {
134139
let expected_len = snappy::decompressed_len(chunk)?;
135140
if expected_len > MAX_CHUNK_SIZE {
@@ -138,7 +143,10 @@ impl Restoration {
138143
}
139144
let len = snappy::decompress_into(chunk, &mut self.snappy_buffer)?;
140145

141-
self.state.feed(&self.snappy_buffer[..len], flag)?;
146+
self.state
147+
.as_mut()
148+
.expect("checked above; qed")
149+
.feed(&self.snappy_buffer[..len], flag)?;
142150

143151
if let Some(ref mut writer) = self.writer.as_mut() {
144152
writer.write_state_chunk(hash, chunk)?;
@@ -177,15 +185,17 @@ impl Restoration {
177185

178186
if !self.is_done() { return Ok(()) }
179187

180-
// verify final state root.
181-
let root = self.state.state_root();
182-
if root != self.final_state_root {
183-
warn!("Final restored state has wrong state root: expected {:?}, got {:?}", self.final_state_root, root);
184-
bail!(TrieError::InvalidStateRoot(root));
185-
}
188+
if let Some(state) = self.state {
189+
// verify final state root.
190+
let root = state.state_root();
191+
if root != self.final_state_root {
192+
warn!("Final restored state has wrong state root: expected {:?}, got {:?}", self.final_state_root, root);
193+
bail!(TrieError::InvalidStateRoot(root));
194+
}
186195

187-
// check for missing code.
188-
self.state.finalize(self.manifest.block_number, self.manifest.block_hash)?;
196+
// check for missing code.
197+
state.finalize(self.manifest.block_number, self.manifest.block_hash)?;
198+
}
189199

190200
// connect out-of-order chunks and verify chain integrity.
191201
self.secondary.finalize(engine)?;
@@ -208,13 +218,11 @@ impl Restoration {
208218
pub type Channel = IoChannel<ClientIoMessage>;
209219

210220
/// Snapshot service parameters.
211-
pub struct ServiceParams {
221+
pub struct ServiceParams<T: ChainRestorationParams> {
212222
/// The consensus engine this is built on.
213223
pub engine: Arc<EthEngine>,
214-
/// The chain's genesis block.
215-
pub genesis_block: Bytes,
216-
/// State pruning algorithm.
217-
pub pruning: Algorithm,
224+
/// Additional chain specific restoration params.
225+
pub chain_params: T,
218226
/// Handler for opening a restoration DB.
219227
pub restoration_db_handler: Box<KeyValueDBHandler>,
220228
/// Async IO channel for sending messages.
@@ -223,42 +231,88 @@ pub struct ServiceParams {
223231
/// Usually "<chain hash>/snapshot"
224232
pub snapshot_root: PathBuf,
225233
/// A handle for database restoration.
226-
pub db_restore: Arc<DatabaseRestore>,
234+
pub db_restore: Arc<DatabaseRestore<T>>,
235+
}
236+
237+
/// Full node specific restoration parameters.
238+
pub struct FullNodeRestorationParams {
239+
/// The chain's genesis block.
240+
pub genesis_block: Bytes,
241+
/// State pruning algorithm.
242+
pub pruning: Algorithm,
243+
}
244+
245+
/// TODO: document
246+
pub trait ChainRestorationParams: Send + Sync {
247+
/// TODO: document
248+
fn restoration(
249+
&self,
250+
manifest: ManifestData,
251+
rest_db: PathBuf,
252+
restoration_db_handler: &KeyValueDBHandler,
253+
writer: Option<LooseWriter>,
254+
engine: &EthEngine,
255+
) -> Result<Restoration, Error>;
256+
257+
/// TODO: document
258+
fn is_light(&self) -> bool {
259+
false
260+
}
261+
}
262+
263+
impl ChainRestorationParams for FullNodeRestorationParams {
264+
fn restoration(
265+
&self,
266+
manifest: ManifestData,
267+
rest_db: PathBuf,
268+
restoration_db_handler: &KeyValueDBHandler,
269+
writer: Option<LooseWriter>,
270+
engine: &EthEngine,
271+
) -> Result<Restoration, Error> {
272+
let params = RestorationParams {
273+
manifest: manifest.clone(),
274+
pruning: self.pruning,
275+
db: restoration_db_handler.open(&rest_db)?,
276+
writer: writer,
277+
genesis: &self.genesis_block,
278+
guard: Guard::new(rest_db),
279+
engine: engine,
280+
};
281+
Restoration::new(params)
282+
}
227283
}
228284

229285
/// `SnapshotService` implementation.
230286
/// This controls taking snapshots and restoring from them.
231-
pub struct Service {
287+
pub struct Service<T: ChainRestorationParams> {
232288
restoration: Mutex<Option<Restoration>>,
233289
restoration_db_handler: Box<KeyValueDBHandler>,
234290
snapshot_root: PathBuf,
235291
io_channel: Mutex<Channel>,
236-
pruning: Algorithm,
237292
status: Mutex<RestorationStatus>,
238293
reader: RwLock<Option<LooseReader>>,
239294
engine: Arc<EthEngine>,
240-
genesis_block: Bytes,
295+
chain_params: T,
241296
state_chunks: AtomicUsize,
242297
block_chunks: AtomicUsize,
243-
db_restore: Arc<DatabaseRestore>,
298+
db_restore: Arc<DatabaseRestore<T>>,
244299
progress: super::Progress,
245300
taking_snapshot: AtomicBool,
246301
restoring_snapshot: AtomicBool,
247302
}
248303

249-
impl Service {
304+
impl<T: ChainRestorationParams> Service<T> {
250305
/// Create a new snapshot service from the given parameters.
251-
pub fn new(params: ServiceParams) -> Result<Self, Error> {
306+
pub fn new(params: ServiceParams<T>) -> Result<Self, Error> {
252307
let mut service = Service {
253308
restoration: Mutex::new(None),
254309
restoration_db_handler: params.restoration_db_handler,
255310
snapshot_root: params.snapshot_root,
256311
io_channel: Mutex::new(params.channel),
257-
pruning: params.pruning,
312+
chain_params: params.chain_params,
258313
status: Mutex::new(RestorationStatus::Inactive),
259314
reader: RwLock::new(None),
260315
engine: params.engine,
261-
genesis_block: params.genesis_block,
262316
state_chunks: AtomicUsize::new(0),
263317
block_chunks: AtomicUsize::new(0),
264318
db_restore: params.db_restore,
@@ -340,7 +394,7 @@ impl Service {
340394
fn replace_client_db(&self) -> Result<(), Error> {
341395
let our_db = self.restoration_db();
342396

343-
self.db_restore.restore_db(&*our_db.to_string_lossy())?;
397+
self.db_restore.restore_db(&*our_db.to_string_lossy(), &self.chain_params)?;
344398
Ok(())
345399
}
346400

@@ -464,20 +518,21 @@ impl Service {
464518
false => None
465519
};
466520

467-
let params = RestorationParams {
468-
manifest: manifest.clone(),
469-
pruning: self.pruning,
470-
db: self.restoration_db_handler.open(&rest_db)?,
471-
writer: writer,
472-
genesis: &self.genesis_block,
473-
guard: Guard::new(rest_db),
474-
engine: &*self.engine,
521+
let state_chunks = if self.chain_params.is_light() {
522+
0
523+
} else {
524+
manifest.state_hashes.len()
475525
};
476-
477-
let state_chunks = manifest.state_hashes.len();
478526
let block_chunks = manifest.block_hashes.len();
479527

480-
*res = Some(Restoration::new(params)?);
528+
*res = Some(ChainRestorationParams::restoration(
529+
&self.chain_params,
530+
manifest.clone(),
531+
rest_db,
532+
&*self.restoration_db_handler,
533+
writer,
534+
&*self.engine,
535+
)?);
481536

482537
self.restoring_snapshot.store(true, Ordering::SeqCst);
483538

@@ -668,7 +723,7 @@ impl Service {
668723
}
669724
}
670725

671-
impl SnapshotService for Service {
726+
impl<T: ChainRestorationParams> SnapshotService for Service<T> {
672727
fn manifest(&self) -> Option<ManifestData> {
673728
self.reader.read().as_ref().map(|r| r.manifest().clone())
674729
}
@@ -752,7 +807,7 @@ impl SnapshotService for Service {
752807
}
753808
}
754809

755-
impl Drop for Service {
810+
impl<T: ChainRestorationParams> Drop for Service<T> {
756811
fn drop(&mut self) {
757812
self.abort_restore();
758813
}

parity/snapshot.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use std::sync::Arc;
2222

2323
use hash::keccak;
2424
use ethcore::account_provider::AccountProvider;
25-
use ethcore::snapshot::{Progress, RestorationStatus, SnapshotService as SS};
25+
use ethcore::snapshot::{Progress, RestorationStatus, SnapshotService as SS, FullNodeRestorationParams};
2626
use ethcore::snapshot::io::{SnapshotReader, PackedReader, PackedWriter};
2727
use ethcore::snapshot::service::Service as SnapshotService;
2828
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType};
@@ -67,7 +67,11 @@ pub struct SnapshotCommand {
6767

6868
// helper for reading chunks from arbitrary reader and feeding them into the
6969
// service.
70-
fn restore_using<R: SnapshotReader>(snapshot: Arc<SnapshotService>, reader: &R, recover: bool) -> Result<(), String> {
70+
fn restore_using<R: SnapshotReader>(
71+
snapshot: Arc<SnapshotService<FullNodeRestorationParams>>,
72+
reader: &R,
73+
recover: bool
74+
) -> Result<(), String> {
7175
let manifest = reader.manifest();
7276

7377
info!("Restoring to block #{} (0x{:?})", manifest.block_number, manifest.block_hash);

0 commit comments

Comments
 (0)