Skip to content
2 changes: 1 addition & 1 deletion rust/rbac-registration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ thiserror = "2.0.11"

c509-certificate = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "c509-certificate-v0.0.3" }
cbork-utils = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "cbork-utils-v0.0.2" }
cardano-blockchain-types = { version = "0.0.8", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "cardano-blockchain-types/v0.0.8" }
cardano-blockchain-types = { version = "0.0.9", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "cardano-blockchain-types/v0.0.9" }
catalyst-types = { version = "0.0.10", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "catalyst-types/v0.0.10" }
102 changes: 67 additions & 35 deletions rust/rbac-registration/src/cardano/cip509/cip509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{

use anyhow::{Context, anyhow};
use cardano_blockchain_types::{
MetadatumLabel, MultiEraBlock, TxnIndex,
MetadatumLabel, MultiEraBlock, StakeAddress, TxnIndex,
hashes::{BLAKE_2B256_SIZE, Blake2b256Hash, TransactionId},
pallas_addresses::{Address, ShelleyAddress},
pallas_primitives::{Nullable, conway},
Expand All @@ -22,6 +22,7 @@ use catalyst_types::{
uuid::UuidV4,
};
use cbork_utils::decode_helper::{decode_bytes, decode_helper, decode_map_len};
use ed25519_dalek::VerifyingKey;
use minicbor::{
Decode, Decoder,
decode::{self},
Expand All @@ -31,8 +32,9 @@ use tracing::warn;
use uuid::Uuid;

use crate::cardano::cip509::{
Payment, PointTxnIdx, RoleData,
C509Cert, LocalRefInt, Payment, PointTxnIdx, RoleData, SimplePublicKeyType, X509DerCert,
decode_context::DecodeContext,
extract_key,
rbac::Cip509RbacMetadata,
types::{PaymentHistory, TxInputHash, ValidationSignature},
utils::Cip0134UriSet,
Expand Down Expand Up @@ -80,7 +82,8 @@ pub struct Cip509 {
origin: PointTxnIdx,
/// A catalyst ID.
///
/// This field is only present in role 0 registrations.
/// This field is only present in role 0 registrations and only for the first
/// registration, which defines a `CatalystId` for the chain.
catalyst_id: Option<CatalystId>,
/// Raw aux data associated with the transaction that CIP509 is attached to,
raw_aux_data: Vec<u8>,
Expand Down Expand Up @@ -180,6 +183,12 @@ impl Cip509 {
validate_self_sign_cert(metadata, &report);
}

// We want to keep `catalyst_id` field only for the first registration,
// which starts a new chain
if cip509.prv_tx_id.is_some() {
cip509.catalyst_id = None;
}

Ok(Some(cip509))
}

Expand Down Expand Up @@ -227,6 +236,48 @@ impl Cip509 {
self.metadata.as_ref().and_then(|m| m.role_data.get(&role))
}

/// Returns signing public key for a role.
/// Would return only signing public keys for the present certificates,
/// if certificate marked as deleted or undefined it would be skipped.
#[must_use]
pub fn signing_public_key_for_role(
&self,
role: RoleId,
) -> Option<VerifyingKey> {
self.metadata.as_ref().and_then(|m| {
let key_ref = m.role_data.get(&role).and_then(|d| d.signing_key())?;
match key_ref.local_ref {
LocalRefInt::X509Certs => {
m.x509_certs.get(key_ref.key_offset).and_then(|c| {
if let X509DerCert::X509Cert(c) = c {
extract_key::x509_key(c).ok()
} else {
None
}
})
},
LocalRefInt::C509Certs => {
m.c509_certs.get(key_ref.key_offset).and_then(|c| {
if let C509Cert::C509Certificate(c) = c {
extract_key::c509_key(c).ok()
} else {
None
}
})
},
LocalRefInt::PubKeys => {
m.pub_keys.get(key_ref.key_offset).and_then(|c| {
if let SimplePublicKeyType::Ed25519(c) = c {
Some(*c)
} else {
None
}
})
},
}
})
}

/// Returns a purpose of this registration.
#[must_use]
pub fn purpose(&self) -> Option<UuidV4> {
Expand Down Expand Up @@ -269,24 +320,13 @@ impl Cip509 {
self.txn_inputs_hash.as_ref()
}

/// Returns a Catalyst ID of this registration if role 0 is present.
/// Returns a Catalyst ID of this registration if role 0 is present and if its a first
/// registration, which defines a `CatalystId` for the chain.
#[must_use]
pub fn catalyst_id(&self) -> Option<&CatalystId> {
self.catalyst_id.as_ref()
}

/// Returns a list of addresses extracted from certificate URIs of a specific role.
#[must_use]
pub fn certificate_addresses(
&self,
role: usize,
) -> HashSet<Address> {
self.metadata
.as_ref()
.map(|m| m.certificate_uris.role_addresses(role))
.unwrap_or_default()
}

/// Return validation signature.
#[must_use]
pub fn validation_signature(&self) -> Option<&ValidationSignature> {
Expand All @@ -305,26 +345,18 @@ impl Cip509 {
self.metadata.as_ref()
}

/// Returns `Cip509` fields consuming the structure if it was successfully decoded and
/// validated otherwise return the problem report that contains all the encountered
/// issues.
///
/// # Errors
///
/// - `Err(ProblemReport)`
pub fn consume(self) -> Result<(UuidV4, Cip509RbacMetadata, PaymentHistory), ProblemReport> {
match (
self.purpose,
self.txn_inputs_hash,
self.metadata,
self.validation_signature,
) {
(Some(purpose), Some(_), Some(metadata), Some(_)) if !self.report.is_problematic() => {
Ok((purpose, metadata, self.payment_history))
},
/// Returns a set of stake addresses.
#[must_use]
pub fn stake_addresses(&self) -> HashSet<StakeAddress> {
self.certificate_uris()
.map(Cip0134UriSet::stake_addresses)
.unwrap_or_default()
}

_ => Err(self.report),
}
/// Returns a payment history map.
#[must_use]
pub fn payment_history(&self) -> &PaymentHistory {
&self.payment_history
}
}

Expand Down
14 changes: 7 additions & 7 deletions rust/rbac-registration/src/cardano/cip509/rbac/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,31 @@ use crate::cardano::cip509::{
#[allow(clippy::module_name_repetitions)]
pub struct Cip509RbacMetadata {
/// A potentially empty list of x509 certificates.
pub x509_certs: Vec<X509DerCert>,
pub(crate) x509_certs: Vec<X509DerCert>,
/// A potentially empty list of c509 certificates.
pub c509_certs: Vec<C509Cert>,
pub(crate) c509_certs: Vec<C509Cert>,
/// A set of URIs contained in both x509 and c509 certificates.
///
/// URIs from different certificate types are stored separately and certificate
/// indexes are preserved too.
///
/// This field isn't present in the encoded format and is populated by processing both
/// `x509_certs` and `c509_certs` fields.
pub certificate_uris: Cip0134UriSet,
pub(crate) certificate_uris: Cip0134UriSet,
/// A list of public keys that can be used instead of storing full certificates.
///
/// Check [this section] to understand how certificates and the public keys list are
/// related.
///
/// [this section]: https://github.com/input-output-hk/catalyst-CIPs/tree/x509-role-registration-metadata/CIP-XXXX#storing-certificates-and-public-key
pub pub_keys: Vec<SimplePublicKeyType>,
pub(crate) pub_keys: Vec<SimplePublicKeyType>,
/// A potentially empty list of revoked certificates.
pub revocation_list: Vec<CertKeyHash>,
pub(crate) revocation_list: Vec<CertKeyHash>,
/// A potentially empty role data.
pub role_data: HashMap<RoleId, RoleData>,
pub(crate) role_data: HashMap<RoleId, RoleData>,
/// Optional map of purpose key data.
/// Empty map if no purpose key data is present.
pub purpose_key_data: HashMap<u16, Vec<u8>>,
pub(crate) purpose_key_data: HashMap<u16, Vec<u8>>,
}

/// The first valid purpose key.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum CertOrPk {

impl CertOrPk {
/// Extract public key from the given certificate or public key.
pub(crate) fn extract_pk(&self) -> Option<VerifyingKey> {
pub(crate) fn extract_public_key(&self) -> Option<VerifyingKey> {
match self {
CertOrPk::X509(Some(x509)) => extract_key::x509_key(x509).ok(),
CertOrPk::C509(Some(c509)) => extract_key::c509_key(c509).ok(),
Expand Down
Loading