Skip to content

Commit f5e8cf8

Browse files
committed
refactor: moved backup writing to base.rs
1 parent 84d4b72 commit f5e8cf8

File tree

3 files changed

+161
-173
lines changed

3 files changed

+161
-173
lines changed

core/service/src/engine/threshold/service/context_manager.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ where
262262

263263
// Then store the results
264264
self.crypto_storage
265+
.inner
265266
.write_backup_keys_with_meta_store(
266267
&context_id,
267268
backup_enc_key,

core/service/src/vault/storage/crypto_material/base.rs

Lines changed: 160 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@
44
//! both centralized and threshold KMS variants.
55
use crate::{
66
anyhow_error_and_warn_log,
7-
cryptography::internal_crypto_types::PrivateSigKey,
7+
backup::{
8+
custodian::InternalCustodianContext,
9+
operator::{BackupCommitments, RecoveryRequest},
10+
},
11+
cryptography::{backup_pke::BackupPublicKey, internal_crypto_types::PrivateSigKey},
812
engine::{context::ContextInfo, threshold::service::ThresholdFheKeys},
913
grpc::metastore_status_service::CustodianMetaStore,
1014
util::meta_store::MetaStore,
1115
vault::{
16+
keychain::KeychainProxy,
1217
storage::{
1318
delete_all_at_request_id, delete_at_request_id, delete_pk_at_request_id,
1419
read_all_data_versioned, store_context_at_request_id, store_pk_at_request_id,
@@ -580,6 +585,159 @@ where
580585
}
581586
}
582587

588+
/// Write the backup keys to the storage and update the meta store.
589+
/// This methods writes all the material associated with backups to storage,
590+
/// and updates the meta store accordingly.
591+
///
592+
/// This means that the public encryption key for backup is written to the public storage.
593+
/// The same goes for the commitments to the custodian shares and the recovery request.
594+
/// Finally the custodian context, with the information about the custodian nodes, is also written to public storage.
595+
/// The private key for decrypting backups is written to the private storage.
596+
#[allow(clippy::too_many_arguments)]
597+
pub async fn write_backup_keys_with_meta_store(
598+
&self,
599+
req_id: &RequestId,
600+
pub_key: BackupPublicKey,
601+
recovery_request: RecoveryRequest,
602+
custodian_context: InternalCustodianContext,
603+
commitments: BackupCommitments,
604+
meta_store: Arc<RwLock<CustodianMetaStore>>,
605+
) {
606+
// use guarded_meta_store as the synchronization point
607+
// all other locks are taken as needed so that we don't lock up
608+
// other function calls too much
609+
let mut guarded_meta_store = meta_store.write().await;
610+
// Lock the storage needed in correct order to avoid deadlocks.
611+
let mut private_storage_guard = self.private_storage.lock().await;
612+
let mut public_storage_guard = self.public_storage.lock().await;
613+
614+
let priv_storage_future = async {
615+
let custodian_context_store_res = store_versioned_at_request_id(
616+
&mut (*private_storage_guard),
617+
req_id,
618+
&custodian_context,
619+
&PrivDataType::CustodianInfo.to_string(),
620+
)
621+
.await;
622+
if let Err(e) = &custodian_context_store_res {
623+
tracing::error!(
624+
"Failed to store custodian context to private storage for request {}: {}",
625+
req_id,
626+
e
627+
);
628+
} else {
629+
log_storage_success(
630+
req_id,
631+
private_storage_guard.info(),
632+
&PrivDataType::CustodianInfo.to_string(),
633+
false,
634+
true,
635+
);
636+
}
637+
custodian_context_store_res.is_ok()
638+
};
639+
let pub_storage_future = async {
640+
let recovery_store_result = store_versioned_at_request_id(
641+
&mut (*public_storage_guard),
642+
req_id,
643+
&recovery_request,
644+
&PubDataType::RecoveryRequest.to_string(),
645+
)
646+
.await;
647+
if let Err(e) = &recovery_store_result {
648+
tracing::error!(
649+
"Failed to store recovery request to the public storage for request {}: {}",
650+
req_id,
651+
e
652+
);
653+
} else {
654+
log_storage_success(
655+
req_id,
656+
public_storage_guard.info(),
657+
&PubDataType::RecoveryRequest.to_string(),
658+
true,
659+
true,
660+
);
661+
}
662+
let commit_store_result = store_versioned_at_request_id(
663+
&mut (*public_storage_guard),
664+
req_id,
665+
&commitments,
666+
&PubDataType::Commitments.to_string(),
667+
)
668+
.await;
669+
if let Err(e) = &recovery_store_result {
670+
tracing::error!(
671+
"Failed to store commitments to the public storage for request {}: {}",
672+
req_id,
673+
e
674+
);
675+
} else {
676+
log_storage_success(
677+
req_id,
678+
public_storage_guard.info(),
679+
&PubDataType::Commitments.to_string(),
680+
true,
681+
true,
682+
);
683+
}
684+
recovery_store_result.is_ok() && commit_store_result.is_ok()
685+
};
686+
let (priv_res, pub_res) = tokio::join!(priv_storage_future, pub_storage_future);
687+
{
688+
// Update meta store
689+
// First we insert the request ID
690+
// Whether things fail or not we can't do much
691+
match guarded_meta_store.insert(req_id) {
692+
Ok(_) => {}
693+
Err(e) => {
694+
tracing::error!("Failed to insert request ID {req_id} into meta store: {e}",);
695+
self.purge_backup_material(req_id, guarded_meta_store).await;
696+
return;
697+
}
698+
};
699+
// If everything is ok, we update the meta store with a success
700+
if priv_res && pub_res {
701+
if let Err(e) = guarded_meta_store.update(req_id, Ok(custodian_context)) {
702+
tracing::error!("Failed to update meta store for request {req_id}: {e}");
703+
self.purge_backup_material(req_id, guarded_meta_store).await;
704+
}
705+
} else {
706+
self.purge_backup_material(req_id, guarded_meta_store).await;
707+
tracing::error!(
708+
"Failed to store backup keys for request {}: priv_res: {}, pub_res: {}",
709+
req_id,
710+
priv_res,
711+
pub_res,
712+
);
713+
}
714+
}
715+
// Finally update the current backup key in the storage
716+
{
717+
match self.backup_vault {
718+
Some(ref vault) => {
719+
let mut guarded_backup_vault = vault.lock().await;
720+
match &mut guarded_backup_vault.keychain {
721+
Some(keychain) => {
722+
if let KeychainProxy::SecretSharing(sharing_chain) = keychain {
723+
// Store the public key in the secret sharing keychain
724+
sharing_chain.set_backup_enc_key(pub_key);
725+
}
726+
},
727+
None => {
728+
tracing::info!(
729+
"No keychain in backup vault, skipping setting backup encryption key for request {req_id}"
730+
);
731+
},
732+
}
733+
},
734+
None => tracing::warn!(
735+
"No backup vault configured, skipping setting backup encryption key for request {req_id}"
736+
),
737+
}
738+
}
739+
}
740+
583741
/// Tries to delete all the data related to a custodian context (used for backup) for a specific context id [RequestId].
584742
/// WARNING: This also deletes ALL backups of a given context. Hence the method should only be used to clean up.
585743
pub async fn purge_backup_material(
@@ -681,6 +839,7 @@ where
681839
}
682840
}
683841

842+
/// Note that we're not storing a shortint decompression key
684843
pub async fn write_decompression_key_with_meta_store(
685844
&self,
686845
req_id: &RequestId,

core/service/src/vault/storage/crypto_material/threshold.rs

Lines changed: 0 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,9 @@ use tfhe::{integer::compression_keys::DecompressionKey, zk::CompactPkeCrs};
1717
use threshold_fhe::execution::tfhe_internals::public_keysets::FhePubKeySet;
1818

1919
use crate::{
20-
backup::{
21-
custodian::InternalCustodianContext,
22-
operator::{BackupCommitments, RecoveryRequest},
23-
},
24-
cryptography::backup_pke::BackupPublicKey,
2520
engine::threshold::service::ThresholdFheKeys,
26-
grpc::metastore_status_service::CustodianMetaStore,
2721
util::meta_store::MetaStore,
2822
vault::{
29-
keychain::KeychainProxy,
3023
storage::{
3124
crypto_material::log_storage_success, store_pk_at_request_id,
3225
store_versioned_at_request_id, Storage, StorageReader,
@@ -304,171 +297,6 @@ impl<PubS: Storage + Send + Sync + 'static, PrivS: Storage + Send + Sync + 'stat
304297
.await
305298
}
306299

307-
/// Write the backup keys to the storage and update the meta store.
308-
/// This methods writes all the material associated with backups to storage,
309-
/// and updates the meta store accordingly.
310-
///
311-
/// This means that the public encryption key for backup is written to the public storage.
312-
/// The same goes for the commitments to the custodian shares and the recovery request.
313-
/// Finally the custodian context, with the information about the custodian nodes, is also written to public storage.
314-
/// The private key for decrypting backups is written to the private storage.
315-
#[allow(clippy::too_many_arguments)]
316-
pub async fn write_backup_keys_with_meta_store(
317-
&self,
318-
req_id: &RequestId,
319-
pub_key: BackupPublicKey,
320-
recovery_request: RecoveryRequest,
321-
custodian_context: InternalCustodianContext,
322-
commitments: BackupCommitments,
323-
meta_store: Arc<RwLock<CustodianMetaStore>>,
324-
) {
325-
// use guarded_meta_store as the synchronization point
326-
// all other locks are taken as needed so that we don't lock up
327-
// other function calls too much
328-
let mut guarded_meta_store = meta_store.write().await;
329-
// Lock the storage needed in correct order to avoid deadlocks.
330-
let mut private_storage_guard = self.inner.private_storage.lock().await;
331-
let mut public_storage_guard = self.inner.public_storage.lock().await;
332-
333-
let priv_storage_future = async {
334-
let custodian_context_store_res = store_versioned_at_request_id(
335-
&mut (*private_storage_guard),
336-
req_id,
337-
&custodian_context,
338-
&PrivDataType::CustodianInfo.to_string(),
339-
)
340-
.await;
341-
if let Err(e) = &custodian_context_store_res {
342-
tracing::error!(
343-
"Failed to store custodian context to private storage for request {}: {}",
344-
req_id,
345-
e
346-
);
347-
} else {
348-
log_storage_success(
349-
req_id,
350-
private_storage_guard.info(),
351-
&PrivDataType::CustodianInfo.to_string(),
352-
false,
353-
true,
354-
);
355-
}
356-
custodian_context_store_res.is_ok()
357-
};
358-
let pub_storage_future = async {
359-
let recovery_store_result = store_versioned_at_request_id(
360-
&mut (*public_storage_guard),
361-
req_id,
362-
&recovery_request,
363-
&PubDataType::RecoveryRequest.to_string(),
364-
)
365-
.await;
366-
if let Err(e) = &recovery_store_result {
367-
tracing::error!(
368-
"Failed to store recovery request to the public storage for request {}: {}",
369-
req_id,
370-
e
371-
);
372-
} else {
373-
log_storage_success(
374-
req_id,
375-
public_storage_guard.info(),
376-
&PubDataType::RecoveryRequest.to_string(),
377-
true,
378-
true,
379-
);
380-
}
381-
let commit_store_result = store_versioned_at_request_id(
382-
&mut (*public_storage_guard),
383-
req_id,
384-
&commitments,
385-
&PubDataType::Commitments.to_string(),
386-
)
387-
.await;
388-
if let Err(e) = &recovery_store_result {
389-
tracing::error!(
390-
"Failed to store commitments to the public storage for request {}: {}",
391-
req_id,
392-
e
393-
);
394-
} else {
395-
log_storage_success(
396-
req_id,
397-
public_storage_guard.info(),
398-
&PubDataType::Commitments.to_string(),
399-
true,
400-
true,
401-
);
402-
}
403-
recovery_store_result.is_ok() && commit_store_result.is_ok()
404-
};
405-
let (priv_res, pub_res) = tokio::join!(priv_storage_future, pub_storage_future);
406-
{
407-
// Update meta store
408-
// First we insert the request ID
409-
// Whether things fail or not we can't do much
410-
match guarded_meta_store.insert(req_id) {
411-
Ok(_) => {}
412-
Err(e) => {
413-
tracing::error!("Failed to insert request ID {req_id} into meta store: {e}",);
414-
self.purge_backup_material(req_id, guarded_meta_store).await;
415-
return;
416-
}
417-
};
418-
// If everything is ok, we update the meta store with a success
419-
if priv_res && pub_res {
420-
if let Err(e) = guarded_meta_store.update(req_id, Ok(custodian_context)) {
421-
tracing::error!("Failed to update meta store for request {req_id}: {e}");
422-
self.purge_backup_material(req_id, guarded_meta_store).await;
423-
}
424-
} else {
425-
self.purge_backup_material(req_id, guarded_meta_store).await;
426-
tracing::error!(
427-
"Failed to store backup keys for request {}: priv_res: {}, pub_res: {}",
428-
req_id,
429-
priv_res,
430-
pub_res,
431-
);
432-
}
433-
}
434-
// Finally update the current backup key in the storage
435-
{
436-
match self.inner.backup_vault {
437-
Some(ref vault) => {
438-
let mut guarded_backup_vault = vault.lock().await;
439-
match &mut guarded_backup_vault.keychain {
440-
Some(keychain) => {
441-
if let KeychainProxy::SecretSharing(sharing_chain) = keychain {
442-
// Store the public key in the secret sharing keychain
443-
sharing_chain.set_backup_enc_key(pub_key);
444-
}
445-
},
446-
None => {
447-
tracing::info!(
448-
"No keychain in backup vault, skipping setting backup encryption key for request {req_id}"
449-
);
450-
},
451-
}
452-
},
453-
None => tracing::warn!(
454-
"No backup vault configured, skipping setting backup encryption key for request {req_id}"
455-
),
456-
}
457-
}
458-
}
459-
460-
/// Tries to delete all the data related to a custodian context (used for backup) for a specific context id [RequestId].
461-
/// WARNING: This also deletes ALL backups of a given context. Hence the method should only be used to clean up.
462-
pub async fn purge_backup_material(
463-
&self,
464-
req_id: &RequestId,
465-
guarded_meta_store: RwLockWriteGuard<'_, CustodianMetaStore>,
466-
) {
467-
self.inner
468-
.purge_backup_material(req_id, guarded_meta_store)
469-
.await
470-
}
471-
472300
/// Tries to delete all the types of key material related to a specific [RequestId].
473301
/// WARNING: This also deletes the BACKUP of the keys. Hence the method should should only be used as cleanup after a failed DKG.
474302
pub async fn purge_key_material(

0 commit comments

Comments
 (0)