Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix backup of light-client db and introduce light-client-db subdirectory #1333

Merged
merged 7 commits into from
May 31, 2023
3 changes: 2 additions & 1 deletion core-primitives/settings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ pub mod files {
pub static SIDECHAIN_PURGE_LIMIT: u64 = 100; // keep the last.. sidechainblocks when purging

// used by enclave
pub const LIGHT_CLIENT_DB: &str = "light_client_db.bin";
/// Path to the light-client db.
pub const LIGHT_CLIENT_DB_PATH: &str = "light_client_db";

pub const RA_DUMP_CERT_DER_FILE: &str = "ra_dump_cert.der";

Expand Down
81 changes: 67 additions & 14 deletions core/parentchain/light-client/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,40 +37,74 @@ use std::{
sync::Arc,
};

pub const DB_FILE: &str = "db.bin";
pub const BACKUP_FILE: &str = "db.bin.backup";

#[derive(Clone, Debug)]
pub struct LightClientStateSeal<B, LightClientState> {
path_buf: PathBuf,
base_path: PathBuf,
db_path: PathBuf,
backup_path: PathBuf,
_phantom: PhantomData<(B, LightClientState)>,
}

impl<B, L> LightClientStateSeal<B, L> {
pub fn new(path: PathBuf) -> Self {
Self { path_buf: path, _phantom: Default::default() }
pub fn new(base_path: PathBuf) -> Result<Self> {
std::fs::create_dir_all(&base_path)?;
Ok(Self {
base_path: base_path.clone(),
db_path: base_path.clone().join(DB_FILE),
backup_path: base_path.join(BACKUP_FILE),
_phantom: Default::default(),
})
}

pub fn base_path(&self) -> &Path {
&self.base_path
}

pub fn db_path(&self) -> &Path {
&self.db_path
}

pub fn backup_path(&self) -> &Path {
&self.backup_path
}

pub fn backup(&self) -> Result<()> {
if self.db_path().exists() {
let _bytes = fs::copy(self.db_path(), self.backup_path())?;
} else {
info!("{} does not exist yet, skipping backup...", self.db_path().display())
}
Ok(())
}
}

impl<B: Block, LightClientState: Decode + Encode + Debug> LightClientSealing<LightClientState>
for LightClientStateSeal<B, LightClientState>
{
fn seal(&self, unsealed: &LightClientState) -> Result<()> {
debug!("backup light client state");
if fs::copy(&self.path(), &self.path().join(".1")).is_err() {
warn!("could not backup previous light client state");
trace!("Backup light client state");

if let Err(e) = self.backup() {
warn!("Could not backup previous light client state: Error: {}", e);
};
debug!("Seal light client State. Current state: {:?}", unsealed);
Ok(unsealed.using_encoded(|bytes| seal(bytes, self.path()))?)

trace!("Seal light client State. Current state: {:?}", unsealed);
Ok(unsealed.using_encoded(|bytes| seal(bytes, self.db_path()))?)
}

fn unseal(&self) -> Result<LightClientState> {
Ok(unseal(self.path()).map(|b| Decode::decode(&mut b.as_slice()))??)
Ok(unseal(self.db_path()).map(|b| Decode::decode(&mut b.as_slice()))??)
}

fn exists(&self) -> bool {
SgxFile::open(self.path()).is_ok()
SgxFile::open(self.db_path()).is_ok()
}

fn path(&self) -> &Path {
&self.path_buf.as_path()
self.db_path()
}
}

Expand Down Expand Up @@ -202,8 +236,11 @@ where

#[cfg(feature = "test")]
pub mod sgx_tests {
use super::{read_or_init_parachain_validator, Arc, LightClientStateSeal};
use crate::{light_client_init_params::SimpleParams, LightClientState, LightValidationState};
use super::{read_or_init_parachain_validator, Arc, LightClientStateSeal, RelayState};
use crate::{
light_client_init_params::SimpleParams, LightClientSealing, LightClientState,
LightValidationState,
};
use itc_parentchain_test::{Block, Header, ParentchainHeaderBuilder};
use itp_sgx_temp_dir::TempDir;
use itp_test::mock::onchain_mock::OnchainMock;
Expand All @@ -219,7 +256,7 @@ pub mod sgx_tests {
pub fn init_parachain_light_client_works() {
let parachain_params = default_simple_params();
let temp_dir = TempDir::with_prefix("init_parachain_light_client_works").unwrap();
let seal = TestSeal::new(temp_dir.path().to_path_buf());
let seal = TestSeal::new(temp_dir.path().to_path_buf()).unwrap();

let validator = read_or_init_parachain_validator::<TestBlock, OnchainMock, _>(
parachain_params.clone(),
Expand All @@ -237,6 +274,22 @@ pub mod sgx_tests {
);
}

pub fn sealing_creates_backup() {
let params = default_simple_params();
let temp_dir = TempDir::with_prefix("sealing_creates_backup").unwrap();
let seal = TestSeal::new(temp_dir.path().to_path_buf()).unwrap();
let state = RelayState::new(params.genesis_header, Default::default()).into();

seal.seal(&state).unwrap();
let unsealed = seal.unseal().unwrap();

assert_eq!(state, unsealed);

// The first seal operation doesn't create a backup, as there is nothing to backup.
seal.seal(&unsealed).unwrap();
assert!(seal.backup_path().exists())
}

// Todo #1293: add a unit test for the grandpa validator, but this needs a little effort for
// setting up correct finality params.
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use sp_runtime::traits::Block as ParentchainBlockTrait;

pub use sp_finality_grandpa::SetId;

#[derive(Encode, Decode, Clone, Debug)]
#[derive(Encode, Decode, Clone, Debug, Eq, PartialEq)]
pub struct LightValidationState<Block: ParentchainBlockTrait> {
pub(crate) relay_state: RelayState<Block>,
}
Expand Down
4 changes: 2 additions & 2 deletions core/parentchain/light-client/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use sp_runtime::{
};
use std::{fmt, vec::Vec};

#[derive(Encode, Decode, Clone, PartialEq)]
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct RelayState<Block: BlockT> {
pub last_finalized_block_header: Block::Header,
pub penultimate_finalized_block_header: Block::Header,
Expand All @@ -35,7 +35,7 @@ pub struct RelayState<Block: BlockT> {
pub scheduled_change: Option<ScheduledChangeAtBlock<Block::Header>>, // Scheduled Authorities change as indicated in the header's digest.
}

#[derive(Encode, Decode, Clone, PartialEq)]
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct ScheduledChangeAtBlock<Header: HeaderT> {
pub at_block: Header::Number,
pub next_authority_list: AuthorityList,
Expand Down
4 changes: 2 additions & 2 deletions enclave-runtime/src/initialization/parentchain/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use codec::Encode;
use itc_parentchain::light_client::{concurrent_access::ValidatorAccess, LightClientState};
use itp_component_container::{ComponentGetter, ComponentInitializer};
use itp_settings::{
files::LIGHT_CLIENT_DB,
files::LIGHT_CLIENT_DB_PATH,
worker_mode::{ProvideWorkerMode, WorkerMode},
};
use std::{path::PathBuf, sync::Arc, vec::Vec};
Expand Down Expand Up @@ -63,7 +63,7 @@ impl FullParachainHandler {

let genesis_header = params.genesis_header.clone();

let light_client_seal = EnclaveLightClientSeal::new(base_path.join(LIGHT_CLIENT_DB));
let light_client_seal = EnclaveLightClientSeal::new(base_path.join(LIGHT_CLIENT_DB_PATH))?;
let validator = itc_parentchain::light_client::io::read_or_init_parachain_validator::<
ParachainBlock,
EnclaveOCallApi,
Expand Down
4 changes: 2 additions & 2 deletions enclave-runtime/src/initialization/parentchain/solochain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use codec::Encode;
use itc_parentchain::light_client::{concurrent_access::ValidatorAccess, LightClientState};
use itp_component_container::{ComponentGetter, ComponentInitializer};
use itp_settings::{
files::LIGHT_CLIENT_DB,
files::LIGHT_CLIENT_DB_PATH,
worker_mode::{ProvideWorkerMode, WorkerMode},
};
use std::{path::PathBuf, sync::Arc, vec::Vec};
Expand Down Expand Up @@ -62,7 +62,7 @@ impl FullSolochainHandler {

let genesis_header = params.genesis_header.clone();

let light_client_seal = EnclaveLightClientSeal::new(base_path.join(LIGHT_CLIENT_DB));
let light_client_seal = EnclaveLightClientSeal::new(base_path.join(LIGHT_CLIENT_DB_PATH))?;
let validator = itc_parentchain::light_client::io::read_or_init_grandpa_validator::<
SolochainBlock,
EnclaveOCallApi,
Expand Down
1 change: 1 addition & 0 deletions enclave-runtime/src/test/tests_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ pub extern "C" fn test_main_entrance() -> size_t {

// light-client-test
itc_parentchain::light_client::io::sgx_tests::init_parachain_light_client_works,
itc_parentchain::light_client::io::sgx_tests::sealing_creates_backup,

// these unit test (?) need an ipfs node running..
// ipfs::test_creates_ipfs_content_struct_works,
Expand Down
10 changes: 5 additions & 5 deletions service/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::error::{Error, ServiceResult};
use codec::Encode;
use itp_enclave_api::{enclave_base::EnclaveBase, Enclave};
use itp_settings::files::{
LIGHT_CLIENT_DB, SHARDS_PATH, SHIELDING_KEY_FILE, SIDECHAIN_STORAGE_PATH, SIGNING_KEY_FILE,
LIGHT_CLIENT_DB_PATH, SHARDS_PATH, SHIELDING_KEY_FILE, SIDECHAIN_STORAGE_PATH, SIGNING_KEY_FILE,
};
use itp_types::ShardIdentifier;
use log::*;
Expand Down Expand Up @@ -96,7 +96,7 @@ fn purge_files(root_directory: &Path) -> ServiceResult<()> {
remove_dir_if_it_exists(root_directory, SHARDS_PATH)?;
remove_dir_if_it_exists(root_directory, SIDECHAIN_STORAGE_PATH)?;

remove_file_if_it_exists(root_directory, LIGHT_CLIENT_DB)?;
remove_file_if_it_exists(root_directory, LIGHT_CLIENT_DB_PATH)?;
remove_file_if_it_exists(root_directory, light_client_backup_file().as_str())?;

Ok(())
Expand All @@ -119,7 +119,7 @@ fn remove_file_if_it_exists(root_directory: &Path, file_name: &str) -> ServiceRe
}

fn light_client_backup_file() -> String {
format!("{}.1", LIGHT_CLIENT_DB)
format!("{}.1", LIGHT_CLIENT_DB_PATH)
}

#[cfg(test)]
Expand All @@ -145,14 +145,14 @@ mod tests {
fs::File::create(&sidechain_db_path.join("sidechain_db_2.bin")).unwrap();
fs::File::create(&sidechain_db_path.join("sidechain_db_3.bin")).unwrap();

fs::File::create(&root_directory.join(LIGHT_CLIENT_DB)).unwrap();
fs::File::create(&root_directory.join(LIGHT_CLIENT_DB_PATH)).unwrap();
fs::File::create(&root_directory.join(light_client_backup_file())).unwrap();

purge_files(&root_directory).unwrap();

assert!(!shards_path.exists());
assert!(!sidechain_db_path.exists());
assert!(!root_directory.join(LIGHT_CLIENT_DB).exists());
assert!(!root_directory.join(LIGHT_CLIENT_DB_PATH).exists());
assert!(!root_directory.join(light_client_backup_file()).exists());
}

Expand Down