Skip to content

Commit 4fd7764

Browse files
committed
fix(cardano-blockchain-types): pass cip36 ProblemReport as context
Signed-off-by: bkioshn <[email protected]>
1 parent a56ba35 commit 4fd7764

File tree

4 files changed

+84
-73
lines changed

4 files changed

+84
-73
lines changed

rust/cardano-blockchain-types/src/metadata/cip36/key_registration.rs

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -75,58 +75,55 @@ enum Cip36KeyRegistrationKeys {
7575
Purpose = 5,
7676
}
7777

78-
impl Decode<'_, ()> for Cip36KeyRegistration {
79-
fn decode(d: &mut Decoder, ctx: &mut ()) -> Result<Self, decode::Error> {
78+
impl Decode<'_, ProblemReport> for Cip36KeyRegistration {
79+
fn decode(d: &mut Decoder, ctx: &mut ProblemReport) -> Result<Self, decode::Error> {
8080
let map_len = decode_map_len(d, "CIP36 Key Registration")?;
8181

8282
let mut cip36_key_registration = Cip36KeyRegistration::default();
8383

8484
// Record of founded keys. Check for duplicate keys in the map
8585
let mut found_keys: Vec<Cip36KeyRegistrationKeys> = Vec::new();
8686

87-
// Record of errors found during decoding
88-
let err_report = ProblemReport::new("CIP36 Key Registration Decoding");
89-
9087
for index in 0..map_len {
9188
let key: u16 = decode_helper(d, "key in CIP36 Key Registration", ctx)?;
9289

9390
if let Some(key) = Cip36KeyRegistrationKeys::from_repr(key) {
9491
match key {
9592
Cip36KeyRegistrationKeys::VotingKey => {
96-
if check_is_key_exist(&found_keys, &key, index, &err_report) {
93+
if check_is_key_exist(&found_keys, &key, index, ctx) {
9794
continue;
9895
}
99-
if let Some((is_cip36, voting_keys)) = decode_voting_key(d, &err_report)? {
96+
if let Some((is_cip36, voting_keys)) = decode_voting_key(d, ctx)? {
10097
cip36_key_registration.is_cip36 = is_cip36;
10198
cip36_key_registration.voting_pks = voting_keys;
10299
}
103100
},
104101
Cip36KeyRegistrationKeys::StakePk => {
105-
if check_is_key_exist(&found_keys, &key, index, &err_report) {
102+
if check_is_key_exist(&found_keys, &key, index, ctx) {
106103
continue;
107104
}
108-
if let Some(stake_pk) = decode_stake_pk(d, &err_report)? {
105+
if let Some(stake_pk) = decode_stake_pk(d, ctx)? {
109106
cip36_key_registration.stake_pk = Some(stake_pk);
110107
}
111108
},
112109
Cip36KeyRegistrationKeys::PaymentAddr => {
113-
if check_is_key_exist(&found_keys, &key, index, &err_report) {
110+
if check_is_key_exist(&found_keys, &key, index, ctx) {
114111
continue;
115112
}
116-
if let Some(shelley_addr) = decode_payment_addr(d, &err_report)? {
113+
if let Some(shelley_addr) = decode_payment_addr(d, ctx)? {
117114
cip36_key_registration.payment_addr = Some(shelley_addr.clone());
118115
cip36_key_registration.is_payable =
119116
Some(!shelley_addr.payment().is_script());
120117
}
121118
},
122119
Cip36KeyRegistrationKeys::Nonce => {
123-
if check_is_key_exist(&found_keys, &key, index, &err_report) {
120+
if check_is_key_exist(&found_keys, &key, index, ctx) {
124121
continue;
125122
}
126123
cip36_key_registration.nonce = Some(decode_nonce(d)?);
127124
},
128125
Cip36KeyRegistrationKeys::Purpose => {
129-
if check_is_key_exist(&found_keys, &key, index, &err_report) {
126+
if check_is_key_exist(&found_keys, &key, index, ctx) {
130127
continue;
131128
}
132129
cip36_key_registration.purpose = decode_purpose(d)?;
@@ -138,35 +135,28 @@ impl Decode<'_, ()> for Cip36KeyRegistration {
138135
}
139136

140137
if !found_keys.contains(&Cip36KeyRegistrationKeys::VotingKey) {
141-
err_report.missing_field(
138+
ctx.missing_field(
142139
"Voting Key",
143140
"Missing required key in CIP36 Key Registration",
144141
);
145142
}
146143

147144
if !found_keys.contains(&Cip36KeyRegistrationKeys::StakePk) {
148-
err_report.missing_field(
145+
ctx.missing_field(
149146
"Stake Public Key",
150147
"Missing required key in CIP36 Key Registration",
151148
);
152149
}
153150

154151
if !found_keys.contains(&Cip36KeyRegistrationKeys::PaymentAddr) {
155-
err_report.missing_field(
152+
ctx.missing_field(
156153
"Payment Address",
157154
"Missing required key in CIP36 Key Registration",
158155
);
159156
}
160157

161158
if !found_keys.contains(&Cip36KeyRegistrationKeys::Nonce) {
162-
err_report.missing_field("Nonce", "Missing required key in CIP36 Key Registration");
163-
}
164-
165-
if err_report.is_problematic() {
166-
return Err(decode::Error::message(
167-
serde_json::to_string(&err_report)
168-
.unwrap_or_else(|_| "Failed to serialize ProblemReport".to_string()),
169-
));
159+
ctx.missing_field("Nonce", "Missing required key in CIP36 Key Registration");
170160
}
171161

172162
Ok(cip36_key_registration)

rust/cardano-blockchain-types/src/metadata/cip36/mod.rs

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use key_registration::Cip36KeyRegistration;
1212
use minicbor::{Decode, Decoder};
1313
use pallas::ledger::addresses::ShelleyAddress;
1414
use registration_witness::Cip36RegistrationWitness;
15-
use validation::validate_cip36;
15+
use validation::{validate_cip36, Cip36Validation};
1616
use voting_pk::VotingPubKey;
1717

1818
use crate::{MetadatumLabel, MultiEraBlock, TxnIndex};
@@ -39,14 +39,17 @@ impl Cip36 {
3939
/// * `txn_idx` - The transaction index that contain the auxiliary data.
4040
/// * `is_catalyst_strict` - Is this a Catalyst strict registration?
4141
///
42+
/// # Returns
43+
/// A tuple containing the CIP-36 registration, the validation result, and a problem report.
44+
///
4245
/// # Errors
4346
///
4447
/// If the CIP-36 key registration or registration witness metadata is not found.
4548
/// or if the CIP-36 key registration or registration witness metadata cannot be
4649
/// decoded.
4750
pub fn new(
4851
block: &MultiEraBlock, txn_idx: TxnIndex, is_catalyst_strict: bool,
49-
) -> anyhow::Result<Self> {
52+
) -> anyhow::Result<(Cip36, Cip36Validation, ProblemReport)> {
5053
let Some(k61284) = block.txn_metadata(txn_idx, MetadatumLabel::CIP036_REGISTRATION) else {
5154
bail!("CIP-36 key registration metadata not found")
5255
};
@@ -60,56 +63,54 @@ impl Cip36 {
6063
let mut key_registration = Decoder::new(k61284.as_ref());
6164
let mut registration_witness = Decoder::new(k61285.as_ref());
6265

63-
let key_registration = match Cip36KeyRegistration::decode(&mut key_registration, &mut ()) {
64-
Ok(mut metadata) => {
65-
let nonce = if is_catalyst_strict && metadata.raw_nonce > Some(slot) {
66-
Some(slot)
67-
} else {
68-
metadata.raw_nonce
69-
};
66+
// Record of errors found during decoding and validation
67+
let mut err_report = ProblemReport::new("CIP36 Registration Decoding and Validation");
7068

71-
metadata.nonce = nonce;
72-
metadata
73-
},
74-
Err(e) => {
75-
bail!("Failed to construct CIP-36 key registration, {e}")
76-
},
77-
};
69+
let key_registration =
70+
match Cip36KeyRegistration::decode(&mut key_registration, &mut err_report) {
71+
Ok(mut metadata) => {
72+
let nonce = if is_catalyst_strict && metadata.raw_nonce > Some(slot) {
73+
Some(slot)
74+
} else {
75+
metadata.raw_nonce
76+
};
77+
78+
metadata.nonce = nonce;
79+
metadata
80+
},
81+
Err(e) => {
82+
bail!("Failed to construct CIP-36 key registration, {e}")
83+
},
84+
};
7885

7986
let registration_witness =
80-
match Cip36RegistrationWitness::decode(&mut registration_witness, &mut ()) {
87+
match Cip36RegistrationWitness::decode(&mut registration_witness, &mut err_report) {
8188
Ok(metadata) => metadata,
8289
Err(e) => {
8390
bail!("Failed to construct CIP-36 registration witness {e}")
8491
},
8592
};
8693

87-
let validation_report = ProblemReport::new("CIP-36 Registration Validation");
8894
// If the code reach here, then the CIP36 decoding is successful.
95+
// Now check whether everything is valid.
8996
let validation = validate_cip36(
9097
&key_registration,
9198
&registration_witness,
9299
is_catalyst_strict,
93100
network,
94101
k61284,
95-
&validation_report,
102+
&err_report,
96103
);
97104

98-
let cip36 = Self {
99-
key_registration,
100-
registration_witness,
101-
is_catalyst_strict,
102-
};
103-
104-
if !validation_report.is_problematic() {
105-
return Ok(cip36);
106-
}
107-
// If there are validation errors, the CIP36 is invalid
108-
bail!(
109-
"CIP-36 validation failed: {cip36:?}, Validation: {validation:?}, Reports: {}",
110-
serde_json::to_string(&validation_report)
111-
.unwrap_or_else(|_| "Failed to serialize ProblemReport".to_string())
112-
)
105+
Ok((
106+
Self {
107+
key_registration,
108+
registration_witness,
109+
is_catalyst_strict,
110+
},
111+
validation,
112+
err_report,
113+
))
113114
}
114115

115116
/// Get the `is_cip36` flag from the registration.

rust/cardano-blockchain-types/src/metadata/cip36/registration_witness.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,10 @@ pub(crate) struct Cip36RegistrationWitness {
2121
pub signature: Option<ed25519_dalek::Signature>,
2222
}
2323

24-
impl Decode<'_, ()> for Cip36RegistrationWitness {
25-
fn decode(d: &mut Decoder, ctx: &mut ()) -> Result<Self, decode::Error> {
24+
impl Decode<'_, ProblemReport> for Cip36RegistrationWitness {
25+
fn decode(d: &mut Decoder, ctx: &mut ProblemReport) -> Result<Self, decode::Error> {
2626
let map_len = decode_map_len(d, "CIP36 Registration Witness")?;
2727

28-
// Record of errors found during decoding
29-
let err_report = ProblemReport::new("CIP36 Registration Witness Decoding");
30-
3128
// Expected only 1 key in the map.
3229
if map_len != 1 {
3330
return Err(decode::Error::message(format!(
@@ -39,7 +36,7 @@ impl Decode<'_, ()> for Cip36RegistrationWitness {
3936

4037
// The key needs to be 1.
4138
if key != 1 {
42-
err_report.invalid_value(
39+
ctx.invalid_value(
4340
"map key",
4441
format!("{key}").as_str(),
4542
"expected key 1",
@@ -50,20 +47,13 @@ impl Decode<'_, ()> for Cip36RegistrationWitness {
5047
let sig_bytes = decode_bytes(d, "CIP36 Registration Witness signature")?;
5148
let signature = ed25519_dalek::Signature::from_slice(&sig_bytes)
5249
.map_err(|_| {
53-
err_report.other(
50+
ctx.other(
5451
"Cannot parse an Ed25519 signature from a byte slice",
5552
"CIP36 Registration Witness signature",
5653
);
5754
})
5855
.ok();
5956

60-
if err_report.is_problematic() {
61-
return Err(decode::Error::message(
62-
serde_json::to_string(&err_report)
63-
.unwrap_or_else(|_| "Failed to serialize ProblemReport".to_string()),
64-
));
65-
}
66-
6757
Ok(Cip36RegistrationWitness { signature })
6858
}
6959
}

rust/cardano-blockchain-types/src/metadata/cip36/validation.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub const SIGNDATA_PREAMBLE: [u8; 4] = [0xA1, 0x19, 0xEF, 0x64];
1818
#[allow(clippy::struct_excessive_bools, clippy::module_name_repetitions)]
1919
#[derive(Clone, Default, Debug)]
2020
#[allow(dead_code)]
21-
pub(crate) struct Cip36Validation {
21+
pub struct Cip36Validation {
2222
/// Is the signature valid? (signature in 61285)
2323
is_valid_signature: bool,
2424
/// Is the payment address on the correct network?
@@ -29,6 +29,36 @@ pub(crate) struct Cip36Validation {
2929
is_valid_purpose: bool,
3030
}
3131

32+
impl Cip36Validation {
33+
/// Is the CIP-36 registration valid?
34+
pub fn is_valid(&self) -> bool {
35+
self.is_valid_signature
36+
&& self.is_valid_payment_address_network
37+
&& self.is_valid_voting_keys
38+
&& self.is_valid_purpose
39+
}
40+
41+
/// Is the signature valid?
42+
pub fn is_valid_signature(&self) -> bool {
43+
self.is_valid_signature
44+
}
45+
46+
/// Is the payment address network tag match the provided network?
47+
pub fn is_valid_payment_address_network(&self) -> bool {
48+
self.is_valid_payment_address_network
49+
}
50+
51+
/// Is the voting keys valid?
52+
pub fn is_valid_voting_keys(&self) -> bool {
53+
self.is_valid_voting_keys
54+
}
55+
56+
/// Is the purpose valid?
57+
pub fn is_valid_purpose(&self) -> bool {
58+
self.is_valid_purpose
59+
}
60+
}
61+
3262
/// Validation for CIP-36
3363
/// The validation include the following:
3464
/// * Signature validation of the registration witness 61285 against the stake public key

0 commit comments

Comments
 (0)