Skip to content

Commit a2b492d

Browse files
committed
chore: complete moving to central module
1 parent fd99222 commit a2b492d

File tree

2 files changed

+135
-159
lines changed

2 files changed

+135
-159
lines changed

rust/rbac-registration/src/registration/cardano/mod.rs

Lines changed: 135 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Chain of Cardano registration data
22
33
mod update_rbac;
4-
pub mod validation;
54

65
use std::{
76
collections::{HashMap, HashSet},
@@ -29,7 +28,6 @@ use crate::{
2928
RoleDataRecord, ValidationSignature,
3029
},
3130
providers::RbacRegistrationProvider,
32-
registration::cardano::validation::RbacValidationError,
3331
};
3432

3533
/// Registration chains.
@@ -103,7 +101,7 @@ impl RegistrationChain {
103101
&self,
104102
report: &ProblemReport,
105103
provider: &Provider,
106-
) -> Result<HashSet<VerifyingKey>, RbacValidationError>
104+
) -> Result<(), RbacValidationError>
107105
where
108106
Provider: RbacRegistrationProvider,
109107
{
@@ -126,7 +124,7 @@ impl RegistrationChain {
126124
}
127125
}
128126

129-
Ok(keys)
127+
Ok(())
130128
}
131129

132130
/// Returns a Catalyst ID.
@@ -310,6 +308,39 @@ impl From<RegistrationChainInner> for RegistrationChain {
310308
}
311309
}
312310

311+
/// An error returned from the `validate_rbac_registration` method.
312+
#[allow(clippy::large_enum_variant)]
313+
pub enum RbacValidationError {
314+
/// A registration is invalid (`report.is_problematic()` returns `true`).
315+
///
316+
/// This variant is inserted to the `rbac_invalid_registration` table.
317+
InvalidRegistration {
318+
/// A Catalyst ID.
319+
catalyst_id: CatalystId,
320+
/// A registration purpose.
321+
purpose: Option<UuidV4>,
322+
/// A problem report.
323+
report: ProblemReport,
324+
},
325+
/// Unable to determine a Catalyst ID of the registration.
326+
///
327+
/// This can happen if a previous transaction ID in the registration is incorrect.
328+
UnknownCatalystId,
329+
/// A "fatal" error occurred during validation.
330+
///
331+
/// This means that the validation wasn't performed properly (usually because of a
332+
/// database failure) and we cannot process the given registration. This error is
333+
/// propagated on a higher level, so there will be another attempt to index that
334+
/// block.
335+
Fatal(anyhow::Error),
336+
}
337+
338+
impl From<anyhow::Error> for RbacValidationError {
339+
fn from(e: anyhow::Error) -> Self {
340+
RbacValidationError::Fatal(e)
341+
}
342+
}
343+
313344
/// Inner structure of registration chain.
314345
#[derive(Debug, Clone)]
315346
struct RegistrationChainInner {
@@ -557,6 +588,7 @@ impl RegistrationChainInner {
557588
/// for `previous_txn`.
558589
/// - Returns [`RbacValidationError::InvalidRegistration`] if address/key duplication
559590
/// or validation inconsistencies are detected.
591+
#[must_use]
560592
pub async fn update_from_previous_txn<Provider>(
561593
&self,
562594
reg: Cip509,
@@ -596,9 +628,6 @@ impl RegistrationChainInner {
596628
}
597629
}
598630

599-
// Store values before consuming the registration.
600-
let stake_addresses = reg.stake_addresses();
601-
602631
// Try to add a new registration to the chain.
603632
let new_chain = chain.update(reg.clone()).ok_or_else(|| {
604633
RbacValidationError::InvalidRegistration {
@@ -609,7 +638,7 @@ impl RegistrationChainInner {
609638
})?;
610639

611640
// Check that new public keys aren't used by other chains.
612-
let public_keys = new_chain.validate_public_keys(&report, provider).await?;
641+
new_chain.validate_public_keys(&report, provider).await?;
613642

614643
// Return an error if any issues were recorded in the report.
615644
if report.is_problematic() {
@@ -622,6 +651,104 @@ impl RegistrationChainInner {
622651

623652
Ok(new_chain)
624653
}
654+
655+
/// Attempts to initialize a new RBAC registration chain
656+
/// from a given CIP-509 registration, ensuring uniqueness of Catalyst ID, stake
657+
/// addresses, and associated public keys.
658+
///
659+
/// # Returns
660+
/// - `Ok((new_chain, validation_result))` if the chain was successfully initialized
661+
/// and validated.
662+
///
663+
/// # Errors
664+
/// - [`RbacValidationError::UnknownCatalystId`]: if `reg` lacks a valid Catalyst ID.
665+
/// - [`RbacValidationError::InvalidRegistration`]: if any functional validation,
666+
/// stake address conflict, or public key duplication occurs.
667+
#[must_use]
668+
pub async fn start_from_provider<Provider>(
669+
&self,
670+
reg: Cip509,
671+
provider: &Provider,
672+
) -> Result<RegistrationChain, RbacValidationError>
673+
where
674+
Provider: RbacRegistrationProvider,
675+
{
676+
let catalyst_id = reg.catalyst_id().map(CatalystId::as_short_id);
677+
let purpose = reg.purpose();
678+
let report = reg.report().to_owned();
679+
680+
// Try to start a new chain.
681+
let new_chain = RegistrationChain::new(reg.clone()).ok_or_else(|| {
682+
if let Some(catalyst_id) = catalyst_id {
683+
RbacValidationError::InvalidRegistration {
684+
catalyst_id,
685+
purpose,
686+
report: report.clone(),
687+
}
688+
} else {
689+
RbacValidationError::UnknownCatalystId
690+
}
691+
})?;
692+
693+
// Verify that a Catalyst ID of this chain is unique.
694+
let catalyst_id = new_chain.catalyst_id().as_short_id();
695+
if provider.is_chain_known(catalyst_id.clone()).await? {
696+
report.functional_validation(
697+
&format!("{catalyst_id} is already used"),
698+
"It isn't allowed to use same Catalyst ID (certificate subject public key) in multiple registration chains",
699+
);
700+
return Err(RbacValidationError::InvalidRegistration {
701+
catalyst_id,
702+
purpose,
703+
report,
704+
});
705+
}
706+
707+
// Validate stake addresses.
708+
let new_addresses = new_chain.stake_addresses();
709+
let mut updated_chains: HashMap<_, HashSet<StakeAddress>> = HashMap::new();
710+
for address in &new_addresses {
711+
if let Some(id) = provider.catalyst_id_from_stake_address(address).await? {
712+
// If an address is used in existing chain then a new chain must have different role
713+
// 0 signing key.
714+
let previous_chain = provider.chain(id.clone())
715+
.await?
716+
.context("{id} is present in 'catalyst_id_for_stake_address', but not in 'rbac_registration'")?;
717+
if previous_chain.get_latest_signing_pk_for_role(&RoleId::Role0)
718+
== new_chain.get_latest_signing_pk_for_role(&RoleId::Role0)
719+
{
720+
report.functional_validation(
721+
&format!("A new registration ({catalyst_id}) uses the same public key as the previous one ({})",
722+
previous_chain.catalyst_id().as_short_id()
723+
),
724+
"It is only allowed to override the existing chain by using different public key",
725+
);
726+
} else {
727+
// The new root registration "takes" an address(es) from the existing chain, so
728+
// that chain needs to be updated.
729+
updated_chains
730+
.entry(id)
731+
.and_modify(|e| {
732+
e.insert(address.clone());
733+
})
734+
.or_insert([address.clone()].into_iter().collect());
735+
}
736+
}
737+
}
738+
739+
// Check that new public keys aren't used by other chains.
740+
new_chain.validate_public_keys(&report, provider).await?;
741+
742+
if report.is_problematic() {
743+
return Err(RbacValidationError::InvalidRegistration {
744+
catalyst_id,
745+
purpose,
746+
report,
747+
});
748+
}
749+
750+
Ok(new_chain)
751+
}
625752
}
626753

627754
/// Perform a check on the validation signature.

rust/rbac-registration/src/registration/cardano/validation.rs

Lines changed: 0 additions & 151 deletions
This file was deleted.

0 commit comments

Comments
 (0)