1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of Tetsy Vapory.

// Tetsy Vapory is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Tetsy Vapory is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Tetsy Vapory.  If not, see <http://www.gnu.org/licenses/>.

use std::sync::{Arc, atomic::AtomicBool};

use blockchain::{BlockChain, BlockChainDB};
use bytes::Bytes;
use client_traits::{BlockChainClient, BlockInfo, DatabaseRestore, BlockChainReset};
use common_types::{
	ids::BlockId,
	errors::{VapcoreError as Error, SnapshotError},
	snapshot::{ManifestData, ChunkSink, Progress, RestorationStatus},
};
use enjen::Engine;
use vapory_types::H256;
use parking_lot::RwLock;

use crate::io::SnapshotWriter;

/// The interface for a snapshot network service.
/// This handles:
///    - restoration of snapshots to temporary databases.
///    - responding to queries for snapshot manifests and chunks
pub trait SnapshotService : Sync + Send {
	/// Query the most recent manifest data.
	fn manifest(&self) -> Option<ManifestData>;

	/// Get the supported range of snapshot version numbers.
	/// `None` indicates warp sync isn't supported by the consensus engine.
	fn supported_versions(&self) -> Option<(u64, u64)>;

	/// Returns a list of the completed chunks
	fn completed_chunks(&self) -> Option<Vec<H256>>;

	/// Get raw chunk for a given hash.
	fn chunk(&self, hash: H256) -> Option<Bytes>;

	/// Ask the snapshot service for the restoration status.
	fn status(&self) -> RestorationStatus;

	/// Begin snapshot restoration.
	/// If a restoration is in progress, this will reset it and clear all data.
	fn begin_restore(&self, manifest: ManifestData);

	/// Abort an in-progress restoration if there is one.
	fn abort_restore(&self);

	/// Feed a raw state chunk to the service to be processed asynchronously.
	/// no-op if not currently restoring.
	fn restore_state_chunk(&self, hash: H256, chunk: Bytes);

	/// Feed a raw block chunk to the service to be processed asynchronously.
	/// no-op if currently restoring.
	fn restore_block_chunk(&self, hash: H256, chunk: Bytes);

	/// Abort in-progress snapshotting if there is one.
	fn abort_snapshot(&self);

	/// Shutdown the Snapshot Service by aborting any ongoing restore
	fn shutdown(&self);
}

/// Restore from secondary snapshot chunks.
pub trait Rebuilder: Send {
	/// Feed a chunk, potentially out of order.
	///
	/// Check `abort_flag` periodically while doing heavy work. If set to `false`, should bail with
	/// `Error::RestorationAborted`.
	fn feed(
		&mut self,
		chunk: &[u8],
		engine: &dyn Engine,
		abort_flag: &AtomicBool,
	) -> Result<(), Error>;

	/// Finalize the restoration. Will be done after all chunks have been
	/// fed successfully.
	///
	/// This should apply the necessary "glue" between chunks,
	/// and verify against the restored state.
	fn finalize(&mut self) -> Result<(), Error>;
}

/// Components necessary for snapshot creation and restoration.
pub trait SnapshotComponents: Send {
	/// Create secondary snapshot chunks; these corroborate the state data
	/// in the state chunks.
	///
	/// Chunks shouldn't exceed the given preferred size, and should be fed
	/// uncompressed into the sink.
	///
	/// This will vary by consensus engine, so it's exposed as a trait.
	fn chunk_all(
		&mut self,
		chain: &BlockChain,
		block_at: H256,
		chunk_sink: &mut ChunkSink,
		progress: &RwLock<Progress>,
		preferred_size: usize,
	) -> Result<(), SnapshotError>;

	/// Create a rebuilder, which will have chunks fed into it in arbitrary
	/// order and then be finalized.
	///
	/// The manifest, a database, and fresh `BlockChain` are supplied.
	///
	/// The engine passed to the `Rebuilder` methods will be the same instance
	/// that created the `SnapshotComponents`.
	fn rebuilder(
		&self,
		chain: BlockChain,
		db: Arc<dyn BlockChainDB>,
		manifest: &ManifestData,
	) -> Result<Box<dyn Rebuilder>, Error>;

	/// Minimum supported snapshot version number.
	fn min_supported_version(&self) -> u64;

	/// Current version number
	fn current_version(&self) -> u64;
}

/// Snapshot related functionality
pub trait SnapshotClient: BlockChainClient + BlockInfo + DatabaseRestore + BlockChainReset {
	/// Take a snapshot at the given block.
	/// If the BlockId is 'Latest', this will default to 1000 blocks behind.
	fn take_snapshot<W: SnapshotWriter + Send>(
		&self,
		writer: W,
		at: BlockId,
		p: &RwLock<Progress>,
	) -> Result<(), Error>;
}

/// Helper trait for broadcasting a block to take a snapshot at.
pub trait Broadcast: Send + Sync {
	/// Start a snapshot from the given block number.
	fn request_snapshot_at(&self, num: u64);
}


/// Helper trait for transforming hashes to block numbers and checking if syncing.
pub trait Oracle: Send + Sync {
	/// Maps a block hash to a block number
	fn to_number(&self, hash: H256) -> Option<u64>;

	/// Are we currently syncing?
	fn is_major_importing(&self) -> bool;
}