Skip to content

Commit f4ac310

Browse files
authored
fix(rust/cardano-blockchain-types): CIP36 payment address type (#233)
* fix(cardano-blockchain-types): cip36 payment address type Signed-off-by: bkioshn <[email protected]> * fix(cardano-blockchain-types): cip36 payment addr comments + payable logic Signed-off-by: bkioshn <[email protected]> --------- Signed-off-by: bkioshn <[email protected]>
1 parent c8cf12a commit f4ac310

File tree

3 files changed

+44
-35
lines changed

3 files changed

+44
-35
lines changed

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

+30-24
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use catalyst_types::{
1212
use cbork_utils::decode_helper::{decode_array_len, decode_bytes, decode_helper, decode_map_len};
1313
use ed25519_dalek::VerifyingKey;
1414
use minicbor::{decode, Decode, Decoder};
15-
use pallas::ledger::addresses::{Address, ShelleyAddress};
15+
use pallas::ledger::addresses::Address;
1616
use strum::FromRepr;
1717

1818
use super::voting_pk::VotingPubKey;
@@ -45,7 +45,7 @@ pub(crate) struct Cip36KeyRegistration {
4545
/// Payment Address to associate with the voting keys.
4646
/// Field 3 in the CIP-36 61284 Spec.
4747
/// None if it is not set.
48-
pub payment_addr: Option<ShelleyAddress>,
48+
pub payment_addr: Option<Address>,
4949
/// Nonce (nonce that has been slot corrected).
5050
/// None if it is not set.
5151
pub nonce: Option<u64>,
@@ -62,6 +62,11 @@ pub(crate) struct Cip36KeyRegistration {
6262
pub is_payable: Option<bool>,
6363
}
6464

65+
/// Header type of Shelley address that are consider as payable.
66+
/// Payable if payment part is a `PaymentKeyHash`
67+
/// <https://cips.cardano.org/cip/CIP-19>
68+
const VALID_PAYABLE_HEADER: [u8; 4] = [0, 2, 4, 6];
69+
6570
/// Enum of CIP36 registration (61284) with its associated unsigned integer key.
6671
#[derive(FromRepr, Debug, PartialEq)]
6772
#[repr(u16)]
@@ -111,12 +116,12 @@ impl Decode<'_, ProblemReport> for Cip36KeyRegistration {
111116
cip36_key_registration.stake_pk = stake_pk;
112117
},
113118
Cip36KeyRegistrationKeys::PaymentAddr => {
114-
let shelley_addr = decode_payment_addr(d, err_report)?;
115-
cip36_key_registration.is_payable = shelley_addr
119+
let address = decode_payment_addr(d, err_report)?;
120+
cip36_key_registration.is_payable = address
116121
.as_ref()
117-
.map(|addr| !addr.payment().is_script())
122+
.map(|addr| VALID_PAYABLE_HEADER.contains(&addr.typeid()))
118123
.or(None);
119-
cip36_key_registration.payment_addr = shelley_addr;
124+
cip36_key_registration.payment_addr = address;
120125
},
121126
Cip36KeyRegistrationKeys::Nonce => {
122127
cip36_key_registration.raw_nonce = Some(decode_nonce(d)?);
@@ -294,16 +299,29 @@ fn decode_stake_pk(
294299
///
295300
/// # Returns
296301
///
297-
/// - The payment address as a `ShelleyAddress`.
298-
/// - None if cannot converted `Vec<u8>` to `ShelleyAddress`.
302+
/// - The payment address as a `Address`.
303+
/// - None if cannot converted `Vec<u8>` to `Address` or the address is a Byron address.
299304
/// - Error if decoding failed.
300305
fn decode_payment_addr(
301306
d: &mut Decoder, err_report: &ProblemReport,
302-
) -> Result<Option<ShelleyAddress>, decode::Error> {
307+
) -> Result<Option<Address>, decode::Error> {
303308
let raw_addr = decode_bytes(d, "CIP36 Key Registration payment address")?;
304309
// Cannot convert raw address to Address type
305-
let address = match Address::from_bytes(&raw_addr) {
306-
Ok(addr) => addr,
310+
match Address::from_bytes(&raw_addr) {
311+
Ok(addr) => {
312+
match addr {
313+
Address::Byron(byron_address) => {
314+
err_report.invalid_value(
315+
"Address",
316+
format!("{byron_address:?}").as_str(),
317+
"Expected non Byron address",
318+
"CIP36 Key Registration payment address",
319+
);
320+
Ok(None)
321+
},
322+
_ => Ok(Some(addr)),
323+
}
324+
},
307325
Err(e) => {
308326
err_report.conversion_error(
309327
"Cardano address",
@@ -312,20 +330,8 @@ fn decode_payment_addr(
312330
"CIP36 Key Registration payment address",
313331
);
314332
// Can't process any further
315-
return Ok(None);
333+
Ok(None)
316334
},
317-
};
318-
319-
if let Address::Shelley(addr) = address {
320-
Ok(Some(addr.clone()))
321-
} else {
322-
err_report.invalid_value(
323-
"Shelley Address",
324-
format!("{address}").as_str(),
325-
"Expected Shelley address",
326-
"CIP36 Key Registration payment address",
327-
);
328-
Ok(None)
329335
}
330336
}
331337

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use catalyst_types::problem_report::ProblemReport;
1010
use ed25519_dalek::VerifyingKey;
1111
use key_registration::Cip36KeyRegistration;
1212
use minicbor::{Decode, Decoder};
13-
use pallas::ledger::addresses::ShelleyAddress;
13+
use pallas::ledger::addresses::Address;
1414
use registration_witness::Cip36RegistrationWitness;
1515
use voting_pk::VotingPubKey;
1616

@@ -247,7 +247,7 @@ impl Cip36 {
247247

248248
/// Get the payment address from the registration.
249249
#[must_use]
250-
pub fn payment_address(&self) -> Option<&ShelleyAddress> {
250+
pub fn payment_address(&self) -> Option<&Address> {
251251
self.key_registration.payment_addr.as_ref()
252252
}
253253

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

+12-9
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,16 @@ impl Cip36 {
7474
return;
7575
};
7676
// Extract the network tag and validate
77-
let network_tag = address.network();
77+
let Some(network_tag) = address.network() else {
78+
// Byron address don't have network tag
79+
self.err_report.missing_field(
80+
"Network tag",
81+
"Validate CIP36 payment address network, network tag not found",
82+
);
83+
self.is_valid_payment_address_network = false;
84+
return;
85+
};
86+
7887
let valid = match self.network {
7988
Network::Mainnet => network_tag.value() == 1,
8089
Network::Preprod | Network::Preview => network_tag.value() == 0,
@@ -164,12 +173,9 @@ mod tests {
164173
// cSpell:disable
165174
let addr = Address::from_bech32("addr_test1qprhw4s70k0vzyhvxp6h97hvrtlkrlcvlmtgmaxdtjz87xrjkctk27ypuv9dzlzxusqse89naweygpjn5dxnygvus05sdq9h07").expect("Failed to create address");
166175
// cSpell:enable
167-
let Address::Shelley(shelley_addr) = addr else {
168-
panic!("Invalid address type")
169-
};
170176
let mut cip36 = create_cip36();
171177
cip36.key_registration = Cip36KeyRegistration {
172-
payment_addr: Some(shelley_addr),
178+
payment_addr: Some(addr),
173179
..Default::default()
174180
};
175181
cip36.validate_payment_address_network();
@@ -183,13 +189,10 @@ mod tests {
183189
// cSpell:disable
184190
let addr = Address::from_bech32("addr_test1qprhw4s70k0vzyhvxp6h97hvrtlkrlcvlmtgmaxdtjz87xrjkctk27ypuv9dzlzxusqse89naweygpjn5dxnygvus05sdq9h07").expect("Failed to create address");
185191
// cSpell:enable
186-
let Address::Shelley(shelley_addr) = addr else {
187-
panic!("Invalid address type")
188-
};
189192
let mut cip36 = create_cip36();
190193
cip36.network = Network::Mainnet;
191194
cip36.key_registration = Cip36KeyRegistration {
192-
payment_addr: Some(shelley_addr),
195+
payment_addr: Some(addr),
193196
..Default::default()
194197
};
195198
cip36.validate_payment_address_network();

0 commit comments

Comments
 (0)