Skip to content

Commit 9a8fbcb

Browse files
CIP509 validation refactoring
1 parent 0b680c7 commit 9a8fbcb

File tree

2 files changed

+41
-75
lines changed
  • rust/rbac-registration/src

2 files changed

+41
-75
lines changed

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

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ pub mod utils;
1010
pub(crate) mod validation;
1111
pub mod x509_chunks;
1212

13+
use anyhow::anyhow;
1314
use minicbor::{
1415
decode::{self},
1516
Decode, Decoder,
1617
};
1718
use pallas::{crypto::hash::Hash, ledger::traverse::MultiEraTx};
1819
use strum_macros::FromRepr;
20+
use tracing::error;
1921
use types::tx_input_hash::TxInputHash;
2022
use uuid::Uuid;
2123
use validation::{
@@ -64,24 +66,6 @@ pub struct Cip509 {
6466
pub validation_signature: ValidationSignature,
6567
}
6668

67-
/// Validation value for CIP509 metadatum.
68-
#[allow(clippy::struct_excessive_bools, clippy::module_name_repetitions)]
69-
#[derive(Debug, PartialEq, Clone, Default)]
70-
pub struct Cip509Validation {
71-
/// Boolean value for the validity of the transaction inputs hash.
72-
pub is_valid_txn_inputs_hash: bool,
73-
/// Boolean value for the validity of the auxiliary data.
74-
pub is_valid_aux: bool,
75-
/// Boolean value for the validity of the stake public key.
76-
pub is_valid_stake_public_key: bool,
77-
/// Boolean value for the validity of the payment key.
78-
pub is_valid_payment_key: bool,
79-
/// Boolean value for the validity of the signing key.
80-
pub is_valid_signing_key: bool,
81-
/// Additional data from the CIP509 validation..
82-
pub additional_data: AdditionalData,
83-
}
84-
8569
/// Additional data from the CIP509 validation.
8670
#[derive(Debug, PartialEq, Clone, Default)]
8771
pub struct AdditionalData {
@@ -177,7 +161,8 @@ impl Decode<'_, ()> for Cip509 {
177161
}
178162

179163
impl Cip509 {
180-
/// Basic validation for CIP509
164+
/// Performs the basic validation of CIP509.
165+
///
181166
/// The validation include the following:
182167
/// * Hashing the transaction inputs within the transaction should match the
183168
/// txn-inputs-hash
@@ -201,36 +186,42 @@ impl Cip509 {
201186
///
202187
/// Note: This CIP509 is still under development and is subject to change.
203188
///
204-
/// # Parameters
205-
/// * `txn` - Transaction data was attached to and to be validated/decoded against.
206-
/// * `validation_report` - Validation report to store the validation result.
207-
pub fn validate(
208-
&self, txn: &MultiEraTx, validation_report: &mut Vec<String>,
209-
) -> Cip509Validation {
189+
/// # Errors
190+
///
191+
/// An error is returned if any of the validation steps is failed. The error contains
192+
/// the description of all failed steps.
193+
pub fn validate(self, txn: &MultiEraTx) -> anyhow::Result<(Self, AdditionalData)> {
194+
let mut validation_report = Vec::new();
195+
210196
let is_valid_txn_inputs_hash =
211-
validate_txn_inputs_hash(self, txn, validation_report).unwrap_or(false);
197+
validate_txn_inputs_hash(&self, txn, &mut validation_report).unwrap_or(false);
212198
let (is_valid_aux, precomputed_aux) =
213-
validate_aux(txn, validation_report).unwrap_or_default();
199+
validate_aux(txn, &mut validation_report).unwrap_or_default();
214200
let mut is_valid_stake_public_key = true;
215201
let mut is_valid_payment_key = true;
216202
let mut is_valid_signing_key = true;
217203
// Validate only role 0
218204
for role in &self.metadata.role_set {
219205
if role.role_number == 0 {
220206
is_valid_stake_public_key =
221-
validate_stake_public_key(self, txn, validation_report).unwrap_or(false);
207+
validate_stake_public_key(&self, txn, &mut validation_report).unwrap_or(false);
222208
is_valid_payment_key =
223-
validate_payment_key(txn, role, validation_report).unwrap_or(false);
224-
is_valid_signing_key = validate_role_singing_key(role, validation_report);
209+
validate_payment_key(txn, role, &mut validation_report).unwrap_or(false);
210+
is_valid_signing_key = validate_role_singing_key(role, &mut validation_report);
225211
}
226212
}
227-
Cip509Validation {
228-
is_valid_txn_inputs_hash,
229-
is_valid_aux,
230-
is_valid_stake_public_key,
231-
is_valid_payment_key,
232-
is_valid_signing_key,
233-
additional_data: AdditionalData { precomputed_aux },
213+
214+
if is_valid_aux
215+
&& is_valid_txn_inputs_hash
216+
&& is_valid_stake_public_key
217+
&& is_valid_payment_key
218+
&& is_valid_signing_key
219+
{
220+
Ok((self, AdditionalData { precomputed_aux }))
221+
} else {
222+
let error = format!("CIP509 validation failed: {validation_report:?}");
223+
error!(error);
224+
Err(anyhow!(error))
234225
}
235226
}
236227
}

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

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub mod role_data;
66

77
use std::{collections::HashMap, sync::Arc};
88

9-
use anyhow::bail;
9+
use anyhow::{bail, Result};
1010
use c509_certificate::c509::C509;
1111
use ed25519_dalek::VerifyingKey;
1212
use pallas::{
@@ -20,7 +20,6 @@ use pallas::{
2020
use payment_history::PaymentHistory;
2121
use point_tx_idx::PointTxIdx;
2222
use role_data::RoleData;
23-
use tracing::error;
2423
use uuid::Uuid;
2524
use x509_cert::certificate::Certificate as X509Certificate;
2625

@@ -32,7 +31,7 @@ use crate::{
3231
pub_key::SimplePublicKeyType,
3332
},
3433
types::cert_key_hash::CertKeyHash,
35-
Cip509, Cip509Validation,
34+
Cip509,
3635
},
3736
utils::general::decremented_index,
3837
};
@@ -60,7 +59,7 @@ impl RegistrationChain {
6059
pub fn new(
6160
point: Point, tracking_payment_keys: &[ShelleyAddress], tx_idx: usize, txn: &MultiEraTx,
6261
cip509: Cip509,
63-
) -> anyhow::Result<Self> {
62+
) -> Result<Self> {
6463
let inner = RegistrationChainInner::new(cip509, tracking_payment_keys, point, tx_idx, txn)?;
6564

6665
Ok(Self {
@@ -81,7 +80,7 @@ impl RegistrationChain {
8180
/// Returns an error if data is invalid
8281
pub fn update(
8382
&self, point: Point, tx_idx: usize, txn: &MultiEraTx, cip509: Cip509,
84-
) -> anyhow::Result<Self> {
83+
) -> Result<Self> {
8584
let new_inner = self.inner.update(point, tx_idx, txn, cip509)?;
8685

8786
Ok(Self {
@@ -180,21 +179,13 @@ impl RegistrationChainInner {
180179
fn new(
181180
cip509: Cip509, tracking_payment_keys: &[ShelleyAddress], point: Point, tx_idx: usize,
182181
txn: &MultiEraTx,
183-
) -> anyhow::Result<Self> {
182+
) -> Result<Self> {
184183
// Should be chain root, return immediately if not
185184
if cip509.prv_tx_id.is_some() {
186185
bail!("Invalid chain root, previous transaction ID should be None.");
187186
}
188187

189-
let mut validation_report = Vec::new();
190-
let validation_data = cip509.validate(txn, &mut validation_report);
191-
192-
// Do the CIP509 validation, ensuring the basic validation pass.
193-
if !is_valid_cip509(&validation_data) {
194-
// Log out the error if any
195-
error!("CIP509 validation failed: {:?}", validation_report);
196-
bail!("CIP509 validation failed, {:?}", validation_report);
197-
}
188+
let (cip509, _additional_data) = cip509.validate(txn)?;
198189

199190
// Add purpose to the list
200191
let purpose = vec![cip509.purpose];
@@ -241,17 +232,10 @@ impl RegistrationChainInner {
241232
/// Returns an error if data is invalid
242233
fn update(
243234
&self, point: Point, tx_idx: usize, txn: &MultiEraTx, cip509: Cip509,
244-
) -> anyhow::Result<Self> {
235+
) -> Result<Self> {
245236
let mut new_inner = self.clone();
246237

247-
let mut validation_report = Vec::new();
248-
let validation_data = cip509.validate(txn, &mut validation_report);
249-
250-
// Do the CIP509 validation, ensuring the basic validation pass.
251-
if !is_valid_cip509(&validation_data) {
252-
error!("CIP509 validation failed: {:?}", validation_report);
253-
bail!("CIP509 validation failed, {:?}", validation_report);
254-
}
238+
let (cip509, _additional_data) = cip509.validate(txn)?;
255239

256240
// Check and update the current transaction ID hash
257241
if let Some(prv_tx_id) = cip509.prv_tx_id {
@@ -293,15 +277,6 @@ impl RegistrationChainInner {
293277
}
294278
}
295279

296-
/// Check if the CIP509 is valid.
297-
fn is_valid_cip509(validation_data: &Cip509Validation) -> bool {
298-
validation_data.is_valid_aux
299-
&& validation_data.is_valid_txn_inputs_hash
300-
&& validation_data.is_valid_stake_public_key
301-
&& validation_data.is_valid_payment_key
302-
&& validation_data.is_valid_signing_key
303-
}
304-
305280
/// Process x509 certificate for chain root.
306281
fn chain_root_x509_certs(
307282
x509_certs: Vec<X509DerCert>, point_tx_idx: &PointTxIdx,
@@ -358,7 +333,7 @@ fn chain_root_c509_certs(
358333
/// Update c509 certificates in the registration chain.
359334
fn update_c509_certs(
360335
new_inner: &mut RegistrationChainInner, c509_certs: Vec<C509Cert>, point_tx_idx: &PointTxIdx,
361-
) -> anyhow::Result<()> {
336+
) -> Result<()> {
362337
for (idx, cert) in c509_certs.into_iter().enumerate() {
363338
match cert {
364339
// Unchanged to that index, so continue
@@ -433,7 +408,7 @@ fn revocations_list(
433408
/// Process the role data for chain root.
434409
fn chain_root_role_data(
435410
role_set: Vec<cip509::rbac::role_data::RoleData>, txn: &MultiEraTx, point_tx_idx: &PointTxIdx,
436-
) -> anyhow::Result<HashMap<u8, (PointTxIdx, RoleData)>> {
411+
) -> Result<HashMap<u8, (PointTxIdx, RoleData)>> {
437412
let mut role_data_map = HashMap::new();
438413
for role_data in role_set {
439414
let signing_key = role_data.role_signing_key.clone();
@@ -463,7 +438,7 @@ fn chain_root_role_data(
463438
fn update_role_data(
464439
inner: &mut RegistrationChainInner, role_set: Vec<cip509::rbac::role_data::RoleData>,
465440
txn: &MultiEraTx, point_tx_idx: &PointTxIdx,
466-
) -> anyhow::Result<()> {
441+
) -> Result<()> {
467442
for role_data in role_set {
468443
// If there is new role singing key, use it, else use the old one
469444
let signing_key = match role_data.role_signing_key {
@@ -509,7 +484,7 @@ fn update_role_data(
509484
/// Helper function for retrieving the Shelley address from the transaction.
510485
fn get_payment_addr_from_tx(
511486
txn: &MultiEraTx, payment_key_ref: Option<i16>,
512-
) -> anyhow::Result<Option<ShelleyAddress>> {
487+
) -> Result<Option<ShelleyAddress>> {
513488
// The index should exist since it pass the basic validation
514489
if let Some(key_ref) = payment_key_ref {
515490
if let MultiEraTx::Conway(tx) = txn {
@@ -550,7 +525,7 @@ fn get_payment_addr_from_tx(
550525
fn update_tracking_payment_history(
551526
tracking_payment_history: &mut HashMap<ShelleyAddress, Vec<PaymentHistory>>, txn: &MultiEraTx,
552527
point_tx_idx: &PointTxIdx,
553-
) -> anyhow::Result<()> {
528+
) -> Result<()> {
554529
if let MultiEraTx::Conway(tx) = txn {
555530
// Conway era -> Post alonzo tx output
556531
for (index, output) in tx.transaction_body.outputs.iter().enumerate() {

0 commit comments

Comments
 (0)