refactor(server::actors::vault): clean up Bootstrap/TryUnseal, remove Bootstrapping state
Bootstrap and TryUnseal now accept a SafeCell<Vec<u8>> seal key directly. The Bootstrapping intermediate state is removed — multi-operator coordination is the responsibility of VaultCoordinator, which calls Bootstrap atomically once all shares are collected.
This commit is contained in:
@@ -1,15 +1,13 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
crypto::{
|
crypto::{
|
||||||
KeyCell, derive_key,
|
KeyCell,
|
||||||
encryption::v1::{self, Nonce},
|
encryption::v1::{self, Nonce},
|
||||||
integrity::v1::HmacSha256,
|
integrity::v1::HmacSha256,
|
||||||
},
|
},
|
||||||
db::{
|
db::{
|
||||||
self,
|
self,
|
||||||
models::{self, OperatorId, OperatorIdentityId, RootKeyHistory, RootKeyHistoryId},
|
models::{self, RootKeyHistory, RootKeyHistoryId},
|
||||||
schema::{self},
|
schema,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use arbiter_crypto::safecell::{SafeCell, SafeCellHandle as _};
|
use arbiter_crypto::safecell::{SafeCell, SafeCellHandle as _};
|
||||||
@@ -17,11 +15,10 @@ use arbiter_crypto::safecell::{SafeCell, SafeCellHandle as _};
|
|||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use diesel::{
|
use diesel::{
|
||||||
ExpressionMethods as _, OptionalExtension, QueryDsl, SelectableHelper,
|
ExpressionMethods as _, OptionalExtension, QueryDsl, SelectableHelper,
|
||||||
dsl::{count, insert_into, update},
|
dsl::{insert_into, update},
|
||||||
select,
|
|
||||||
};
|
};
|
||||||
use diesel_async::{AsyncConnection, RunQueryDsl};
|
use diesel_async::{AsyncConnection, RunQueryDsl};
|
||||||
use hmac::{KeyInit as _, Mac as _, digest::common};
|
use hmac::{KeyInit as _, Mac as _};
|
||||||
use kameo::{Actor, Reply, actor::ActorRef, messages};
|
use kameo::{Actor, Reply, actor::ActorRef, messages};
|
||||||
use kameo_actors::message_bus::{MessageBus, Publish};
|
use kameo_actors::message_bus::{MessageBus, Publish};
|
||||||
use strum::{EnumDiscriminants, IntoDiscriminant};
|
use strum::{EnumDiscriminants, IntoDiscriminant};
|
||||||
@@ -65,15 +62,6 @@ pub enum Error {
|
|||||||
BrokenDatabase,
|
BrokenDatabase,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum UnsealError {}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum BootstrapError {
|
|
||||||
#[error("That operator already contributed his share")]
|
|
||||||
AlreadyContributed,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Unsealed {
|
struct Unsealed {
|
||||||
root_key_history_id: RootKeyHistoryId,
|
root_key_history_id: RootKeyHistoryId,
|
||||||
root_key: KeyCell,
|
root_key: KeyCell,
|
||||||
@@ -85,15 +73,8 @@ enum State {
|
|||||||
#[default]
|
#[default]
|
||||||
Unbootstrapped,
|
Unbootstrapped,
|
||||||
|
|
||||||
Bootstrapping {
|
|
||||||
declared_operators: u64,
|
|
||||||
current_passphrases: HashMap<OperatorIdentityId, SafeCell<Vec<u8>>>,
|
|
||||||
},
|
|
||||||
|
|
||||||
Sealed {
|
Sealed {
|
||||||
threshold: u64, // basically, quorum size
|
|
||||||
root_key_history_id: RootKeyHistoryId,
|
root_key_history_id: RootKeyHistoryId,
|
||||||
current_shares: HashMap<OperatorId, SafeCell<Vec<u8>>>,
|
|
||||||
},
|
},
|
||||||
Unsealed(Unsealed),
|
Unsealed(Unsealed),
|
||||||
}
|
}
|
||||||
@@ -121,17 +102,9 @@ impl Vault {
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
match root_key_history {
|
match root_key_history {
|
||||||
Some(root_key_history) => {
|
Some(root_key_history) => State::Sealed {
|
||||||
let operator_count: i64 = schema::operator::table
|
|
||||||
.count()
|
|
||||||
.get_result(&mut conn)
|
|
||||||
.await?;
|
|
||||||
State::Sealed {
|
|
||||||
root_key_history_id: root_key_history.id,
|
root_key_history_id: root_key_history.id,
|
||||||
current_shares: HashMap::default(),
|
},
|
||||||
threshold: shamir_threshold(operator_count.cast_unsigned()), // invariant: db couldn't return negative number of rows
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => State::Unbootstrapped,
|
None => State::Unbootstrapped,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -139,7 +112,7 @@ impl Vault {
|
|||||||
Ok(Self { db, state, events })
|
Ok(Self { db, state, events })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exclusive transaction to avoid race condtions if multiple vaults write
|
// Exclusive transaction to avoid race conditions if multiple vaults write
|
||||||
// additional layer of protection against nonce-reuse
|
// additional layer of protection against nonce-reuse
|
||||||
async fn get_new_nonce(
|
async fn get_new_nonce(
|
||||||
pool: &db::DatabasePool,
|
pool: &db::DatabasePool,
|
||||||
@@ -180,37 +153,33 @@ impl Vault {
|
|||||||
const fn expect_unsealed(state: &mut State) -> Result<&mut Unsealed, Error> {
|
const fn expect_unsealed(state: &mut State) -> Result<&mut Unsealed, Error> {
|
||||||
match state {
|
match state {
|
||||||
State::Unsealed(unsealed) => Ok(unsealed),
|
State::Unsealed(unsealed) => Ok(unsealed),
|
||||||
State::Bootstrapping { .. } => Err(Error::NotBootstrapped),
|
|
||||||
State::Unbootstrapped => Err(Error::NotBootstrapped),
|
State::Unbootstrapped => Err(Error::NotBootstrapped),
|
||||||
State::Sealed { .. } => Err(Error::Sealed),
|
State::Sealed { .. } => Err(Error::Sealed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn finalize_bootstrap(&mut self) -> Result<(), Error> {
|
#[messages]
|
||||||
let State::Bootstrapping {
|
impl Vault {
|
||||||
declared_operators,
|
#[message]
|
||||||
current_passphrases,
|
pub async fn bootstrap(&mut self, seal_key_raw: SafeCell<Vec<u8>>) -> Result<(), Error> {
|
||||||
} = &mut self.state
|
if !matches!(&self.state, State::Unbootstrapped) {
|
||||||
else {
|
|
||||||
return Err(Error::AlreadyBootstrapped);
|
return Err(Error::AlreadyBootstrapped);
|
||||||
};
|
}
|
||||||
|
|
||||||
let mut root_key = KeyCell::new_secure_random();
|
let mut root_key = KeyCell::new_secure_random();
|
||||||
let root_key_salt = v1::generate_salt();
|
let mut seal_key = KeyCell::try_from(seal_key_raw).map_err(|()| Error::InvalidKey)?;
|
||||||
|
|
||||||
let mut seal_key = KeyCell::new_secure_random();
|
|
||||||
|
|
||||||
let shares = seal_key.0.read_inline(|seal_key| {
|
|
||||||
generate_shamir_shares(current_passphrases.len() as u64, seal_key.as_slice())
|
|
||||||
});
|
|
||||||
|
|
||||||
// Zero nonces are fine because they are one-time
|
// Zero nonces are fine because they are one-time
|
||||||
let root_key_nonce = Nonce::default();
|
let root_key_nonce = Nonce::default();
|
||||||
let data_encryption_nonce = Nonce::default();
|
let data_encryption_nonce = Nonce::default();
|
||||||
|
|
||||||
let root_key_ciphertext: Vec<u8> = root_key.0.read_inline(|reader| {
|
// Generate salt (kept for schema compat)
|
||||||
let root_key_reader = reader.as_slice();
|
let root_key_salt = v1::generate_salt();
|
||||||
|
|
||||||
|
let root_key_ciphertext: Vec<u8> = root_key.0.read_inline(|rk| {
|
||||||
seal_key
|
seal_key
|
||||||
.encrypt(&root_key_nonce, v1::ROOT_KEY_TAG, root_key_reader)
|
.encrypt(&root_key_nonce, v1::ROOT_KEY_TAG, rk.as_slice())
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
error!(?err, "Fatal bootstrap error");
|
error!(?err, "Fatal bootstrap error");
|
||||||
Error::Encryption(err)
|
Error::Encryption(err)
|
||||||
@@ -222,16 +191,6 @@ impl Vault {
|
|||||||
|
|
||||||
let root_key_history_id = conn
|
let root_key_history_id = conn
|
||||||
.transaction(async |conn| {
|
.transaction(async |conn| {
|
||||||
for ((operator_id, raw_passphrase), raw_share) in
|
|
||||||
current_passphrases.iter_mut().zip(shares.iter())
|
|
||||||
{
|
|
||||||
let salt = v1::generate_salt();
|
|
||||||
let mut share_seal_key = derive_key(&mut raw_passphrase, &salt);
|
|
||||||
let share_encryption_nonce = Nonce::default();
|
|
||||||
|
|
||||||
let share_key = derive_key(&mut raw_passphrase, &salt);
|
|
||||||
}
|
|
||||||
|
|
||||||
let root_key_history_id = insert_into(schema::root_key_history::table)
|
let root_key_history_id = insert_into(schema::root_key_history::table)
|
||||||
.values(&models::NewRootKeyHistory {
|
.values(&models::NewRootKeyHistory {
|
||||||
ciphertext: root_key_ciphertext.clone(),
|
ciphertext: root_key_ciphertext.clone(),
|
||||||
@@ -266,82 +225,28 @@ impl Vault {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Seal / unseal / bootstrap stuff. Will be separated into another actor, eventually
|
|
||||||
#[messages]
|
|
||||||
impl Vault {
|
|
||||||
#[message]
|
|
||||||
pub async fn start_bootstrap(&mut self, declared_operators: u64) -> Result<(), Error> {
|
|
||||||
if !matches!(&self.state, State::Unbootstrapped) {
|
|
||||||
return Err(Error::AlreadyBootstrapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.state = State::Bootstrapping {
|
|
||||||
declared_operators,
|
|
||||||
current_passphrases: HashMap::default(),
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[message]
|
#[message]
|
||||||
pub async fn contribute_bootstrap(
|
pub async fn try_unseal(&mut self, seal_key_raw: SafeCell<Vec<u8>>) -> Result<(), Error> {
|
||||||
&mut self,
|
|
||||||
operator: OperatorIdentityId,
|
|
||||||
key_raw: SafeCell<Vec<u8>>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let State::Bootstrapping {
|
|
||||||
current_passphrases,
|
|
||||||
declared_operators,
|
|
||||||
} = &mut self.state
|
|
||||||
else {
|
|
||||||
return Err(Error::AlreadyBootstrapped);
|
|
||||||
};
|
|
||||||
|
|
||||||
if current_passphrases.contains_key(&operator) {
|
|
||||||
return Err(Error::AlreadyBootstrapped);
|
|
||||||
}
|
|
||||||
current_passphrases.insert(operator, key_raw);
|
|
||||||
|
|
||||||
if current_passphrases.len() == declared_operators {
|
|
||||||
return self.finalize_bootstrap(seal_key_raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[message]
|
|
||||||
pub async fn contribute_unseal(
|
|
||||||
&mut self,
|
|
||||||
operator: OperatorId,
|
|
||||||
key_raw: SafeCell<Vec<u8>>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let State::Sealed {
|
let State::Sealed {
|
||||||
root_key_history_id,
|
root_key_history_id,
|
||||||
current_shares,
|
|
||||||
} = &self.state
|
} = &self.state
|
||||||
else {
|
else {
|
||||||
return Err(Error::NotBootstrapped);
|
return Err(Error::NotBootstrapped);
|
||||||
};
|
};
|
||||||
|
let root_key_history_id = *root_key_history_id;
|
||||||
|
|
||||||
// We don't want to hold connection while doing expensive KDF work
|
// We don't want to hold connection while doing expensive work
|
||||||
let current_key = {
|
let current_key = {
|
||||||
let mut conn = self.db.get().await?;
|
let mut conn = self.db.get().await?;
|
||||||
schema::root_key_history::table
|
schema::root_key_history::table
|
||||||
.filter(schema::root_key_history::id.eq(*root_key_history_id))
|
.filter(schema::root_key_history::id.eq(root_key_history_id))
|
||||||
.select(RootKeyHistory::as_select())
|
.select(RootKeyHistory::as_select())
|
||||||
.first(&mut conn)
|
.first(&mut conn)
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
|
|
||||||
let salt = ¤t_key.salt;
|
let mut seal_key = KeyCell::try_from(seal_key_raw).map_err(|()| Error::InvalidKey)?;
|
||||||
let salt = v1::Salt::try_from(salt.as_slice()).map_err(|_| {
|
|
||||||
error!("Broken database: invalid salt for root key");
|
|
||||||
Error::BrokenDatabase
|
|
||||||
})?;
|
|
||||||
let mut seal_key = derive_key(key_raw, &salt);
|
|
||||||
|
|
||||||
let mut root_key = SafeCell::new(current_key.ciphertext.clone());
|
|
||||||
|
|
||||||
let nonce =
|
let nonce =
|
||||||
Nonce::try_from(current_key.root_key_encryption_nonce.as_slice()).map_err(|()| {
|
Nonce::try_from(current_key.root_key_encryption_nonce.as_slice()).map_err(|()| {
|
||||||
@@ -349,19 +254,22 @@ impl Vault {
|
|||||||
Error::BrokenDatabase
|
Error::BrokenDatabase
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let mut root_key_bytes = SafeCell::new(current_key.ciphertext.clone());
|
||||||
seal_key
|
seal_key
|
||||||
.decrypt_in_place(&nonce, v1::ROOT_KEY_TAG, &mut root_key)
|
.decrypt_in_place(&nonce, v1::ROOT_KEY_TAG, &mut root_key_bytes)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
error!(?err, "Failed to unseal root key: invalid seal key");
|
error!(?err, "Failed to unseal root key: invalid seal key");
|
||||||
Error::InvalidKey
|
Error::InvalidKey
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let root_key = KeyCell::try_from(root_key_bytes).map_err(|()| {
|
||||||
|
error!("Broken database: invalid encryption key size");
|
||||||
|
Error::BrokenDatabase
|
||||||
|
})?;
|
||||||
|
|
||||||
self.state = State::Unsealed(Unsealed {
|
self.state = State::Unsealed(Unsealed {
|
||||||
root_key_history_id: current_key.id,
|
root_key_history_id: current_key.id,
|
||||||
root_key: KeyCell::try_from(root_key).map_err(|err| {
|
root_key,
|
||||||
error!(?err, "Broken database: invalid encryption key size");
|
|
||||||
Error::BrokenDatabase
|
|
||||||
})?,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("Vault unsealed successfully");
|
info!("Vault unsealed successfully");
|
||||||
@@ -379,7 +287,6 @@ impl Vault {
|
|||||||
|
|
||||||
self.state = State::Sealed {
|
self.state = State::Sealed {
|
||||||
root_key_history_id: *root_key_history_id,
|
root_key_history_id: *root_key_history_id,
|
||||||
current_shares: HashMap::new(),
|
|
||||||
};
|
};
|
||||||
let _ = self.events.tell(Publish(events::VaultResealed)).await;
|
let _ = self.events.tell(Publish(events::VaultResealed)).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -466,11 +373,9 @@ impl Vault {
|
|||||||
root_key_history_id,
|
root_key_history_id,
|
||||||
} = Self::expect_unsealed(&mut self.state)?;
|
} = Self::expect_unsealed(&mut self.state)?;
|
||||||
|
|
||||||
let mut hmac = root_key
|
let mut hmac = root_key.0.read_inline(|k| {
|
||||||
.0
|
HmacSha256::new_from_slice(k)
|
||||||
.read_inline(|k| match HmacSha256::new_from_slice(k) {
|
.unwrap_or_else(|_| unreachable!("HMAC accepts keys of any size"))
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) => unreachable!("HMAC accepts keys of any size"),
|
|
||||||
});
|
});
|
||||||
hmac.update(&root_key_history_id.to_raw().to_be_bytes());
|
hmac.update(&root_key_history_id.to_raw().to_be_bytes());
|
||||||
hmac.update(&mac_input);
|
hmac.update(&mac_input);
|
||||||
@@ -495,11 +400,9 @@ impl Vault {
|
|||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut hmac = root_key
|
let mut hmac = root_key.0.read_inline(|k| {
|
||||||
.0
|
HmacSha256::new_from_slice(k)
|
||||||
.read_inline(|k| match HmacSha256::new_from_slice(k) {
|
.unwrap_or_else(|_| unreachable!("HMAC accepts keys of any size"))
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) => unreachable!("HMAC accepts keys of any size"),
|
|
||||||
});
|
});
|
||||||
hmac.update(&key_version.to_raw().to_be_bytes());
|
hmac.update(&key_version.to_raw().to_be_bytes());
|
||||||
hmac.update(&mac_input);
|
hmac.update(&mac_input);
|
||||||
@@ -508,42 +411,6 @@ impl Vault {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// According to the spec, the quorum is 50% + 1
|
|
||||||
/// with exception for 1 and 2 operators, those require exactly the number of operators registered
|
|
||||||
fn shamir_threshold(comittee_size: u64) -> u64 {
|
|
||||||
if comittee_size == 2 || comittee_size == 1 {
|
|
||||||
return comittee_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
let half_comittee = match comittee_size % 2 != 0 {
|
|
||||||
true => (comittee_size - 1) / 2,
|
|
||||||
false => comittee_size / 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
half_comittee + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Beware: this function accepts raw key references (without memory protection)
|
|
||||||
fn generate_shamir_shares(threshold: u64, key: &[u8]) -> Vec<SafeCell<Vec<u8>>> {
|
|
||||||
use vsss_rs::{shamir, *};
|
|
||||||
|
|
||||||
type P256Share = DefaultShare<IdentifierPrimeField<Scalar>, IdentifierPrimeField<Scalar>>;
|
|
||||||
|
|
||||||
let mut osrng = rand_core::OsRng::default();
|
|
||||||
let sk = SecretKey::random(&mut osrng);
|
|
||||||
let nzs = sk.to_nonzero_scalar();
|
|
||||||
let shared_secret = IdentifierPrimeField(*nzs.as_ref());
|
|
||||||
let res = shamir::split_secret::<P256Share>(2, 3, &shared_secret, &mut osrng);
|
|
||||||
assert!(res.is_ok());
|
|
||||||
let shares = res.unwrap();
|
|
||||||
let res = shares.combine();
|
|
||||||
assert!(res.is_ok());
|
|
||||||
let scalar = res.unwrap();
|
|
||||||
let nzs_dup = NonZeroScalar::from_repr(scalar.0.to_repr()).unwrap();
|
|
||||||
let sk_dup = SecretKey::from(nzs_dup);
|
|
||||||
assert_eq!(sk_dup.to_bytes(), sk.to_bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::actors::GlobalActors;
|
use crate::actors::GlobalActors;
|
||||||
@@ -555,8 +422,8 @@ mod tests {
|
|||||||
let mut actor = Vault::new(db.clone(), GlobalActors::spawn_message_bus())
|
let mut actor = Vault::new(db.clone(), GlobalActors::spawn_message_bus())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let seal_key = SafeCell::new(b"test-seal-key".to_vec());
|
let seal_key = SafeCell::new([0u8; 32].to_vec());
|
||||||
actor.finalize_bootstrap(seal_key).await.unwrap();
|
actor.bootstrap(seal_key).await.unwrap();
|
||||||
actor
|
actor
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,12 +432,12 @@ mod tests {
|
|||||||
async fn nonce_monotonic_even_when_nonce_allocation_interleaves() {
|
async fn nonce_monotonic_even_when_nonce_allocation_interleaves() {
|
||||||
let db = db::create_test_pool().await;
|
let db = db::create_test_pool().await;
|
||||||
let mut actor = bootstrapped_actor(&db).await;
|
let mut actor = bootstrapped_actor(&db).await;
|
||||||
let root_key_history_id = match actor.state {
|
let State::Unsealed(Unsealed {
|
||||||
State::Unsealed(Unsealed {
|
|
||||||
root_key_history_id,
|
root_key_history_id,
|
||||||
..
|
..
|
||||||
}) => root_key_history_id,
|
}) = actor.state
|
||||||
_ => panic!("expected unsealed state"),
|
else {
|
||||||
|
panic!("expected unsealed state");
|
||||||
};
|
};
|
||||||
|
|
||||||
let n1 = Vault::get_new_nonce(&db, root_key_history_id)
|
let n1 = Vault::get_new_nonce(&db, root_key_history_id)
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ pub(super) async fn dispatch(
|
|||||||
VaultRequestPayload::QueryState(()) => {
|
VaultRequestPayload::QueryState(()) => {
|
||||||
let state = match actor.ask(HandleQueryVaultState {}).await {
|
let state = match actor.ask(HandleQueryVaultState {}).await {
|
||||||
Ok(VaultState::Unbootstrapped) => ProtoVaultState::Unbootstrapped,
|
Ok(VaultState::Unbootstrapped) => ProtoVaultState::Unbootstrapped,
|
||||||
Ok(VaultState::Bootstrapping) => ProtoVaultState::Boostrapping,
|
|
||||||
Ok(VaultState::Sealed) => ProtoVaultState::Sealed,
|
Ok(VaultState::Sealed) => ProtoVaultState::Sealed,
|
||||||
Ok(VaultState::Unsealed) => ProtoVaultState::Unsealed,
|
Ok(VaultState::Unsealed) => ProtoVaultState::Unsealed,
|
||||||
Err(SendError::HandlerError(Error::Internal)) => ProtoVaultState::Error,
|
Err(SendError::HandlerError(Error::Internal)) => ProtoVaultState::Error,
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ async fn handle_query_vault_state(
|
|||||||
let state = match actor.ask(HandleQueryVaultState {}).await {
|
let state = match actor.ask(HandleQueryVaultState {}).await {
|
||||||
Ok(VaultState::Unbootstrapped) => ProtoVaultState::Unbootstrapped,
|
Ok(VaultState::Unbootstrapped) => ProtoVaultState::Unbootstrapped,
|
||||||
Ok(VaultState::Sealed) => ProtoVaultState::Sealed,
|
Ok(VaultState::Sealed) => ProtoVaultState::Sealed,
|
||||||
Ok(VaultState::Bootstrapping) => ProtoVaultState::Boostrapping,
|
|
||||||
Ok(VaultState::Unsealed) => ProtoVaultState::Unsealed,
|
Ok(VaultState::Unsealed) => ProtoVaultState::Unsealed,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(error = ?err, "Failed to query vault state");
|
warn!(error = ?err, "Failed to query vault state");
|
||||||
|
|||||||
Reference in New Issue
Block a user