From eff9b6b2fd27f57348d00a99ee9f3dc74ce90762 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 2 Dec 2024 14:01:25 +0700 Subject: [PATCH 1/6] fix: payment key shelley address and add test for registration chain Signed-off-by: bkioshn --- .../cardano/cip19_shelley_addr.rs | 54 +++++++ .../src/registration/cardano/mod.rs | 141 +++++++++++++++--- .../src/registration/cardano/role_data.rs | 11 +- .../src/test_data/cardano/conway_4.block | 1 + 4 files changed, 180 insertions(+), 27 deletions(-) create mode 100644 rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs create mode 100644 rust/rbac-registration/src/test_data/cardano/conway_4.block diff --git a/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs b/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs new file mode 100644 index 0000000000..5717e07a8b --- /dev/null +++ b/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs @@ -0,0 +1,54 @@ +//! CIP-0019 Shelley Addresses +//! there are currently 8 types of Shelley addresses +//! Header type Payment Part Delegation Part +//! (0) `PaymentKeyHash` `StakeKeyHash` +//! (1) `ScriptHash` `StakeKeyHash` +//! (2) `PaymentKeyHash` `ScriptHash` +//! (3) `ScriptHash` `ScriptHash` +//! (4) `PaymentKeyHash` `Pointer` +//! (5) `ScriptHash` `Pointer` +//! (6) `PaymentKeyHash` ø +//! (7) `ScriptHash` ø + +use pallas::codec::utils::Bytes; + +/// CIP-0019 Shelley Addresses (only support type 0 - 5) +#[derive(PartialEq, Clone, Eq, Hash)] +pub struct Cip19ShelleyAddrs([u8; 57]); + +impl From<[u8; 57]> for Cip19ShelleyAddrs { + fn from(bytes: [u8; 57]) -> Self { + Cip19ShelleyAddrs(bytes) + } +} + +impl Default for Cip19ShelleyAddrs { + fn default() -> Self { + Self([0; 57]) + } +} + +impl TryFrom for Cip19ShelleyAddrs { + type Error = &'static str; + + fn try_from(bytes: Bytes) -> Result { + let byte_vec: Vec = bytes.into(); + + if byte_vec.len() != 57 { + return Err("Invalid length for Ed25519 public key: expected 57 bytes."); + } + + let byte_array: [u8; 57] = byte_vec + .try_into() + .map_err(|_| "Failed to convert Vec to [u8; 32]")?; + + Ok(Cip19ShelleyAddrs::from(byte_array)) + } +} + +impl From for Bytes { + fn from(val: Cip19ShelleyAddrs) -> Self { + let vec: Vec = val.0.to_vec(); + Bytes::from(vec) + } +} diff --git a/rust/rbac-registration/src/registration/cardano/mod.rs b/rust/rbac-registration/src/registration/cardano/mod.rs index 318772903a..a6cbb0b1b9 100644 --- a/rust/rbac-registration/src/registration/cardano/mod.rs +++ b/rust/rbac-registration/src/registration/cardano/mod.rs @@ -1,5 +1,6 @@ //! Chain of Cardano registration data +pub mod cip19_shelley_addr; pub mod payment_history; pub mod point_tx_idx; pub mod role_data; @@ -8,6 +9,7 @@ use std::{collections::HashMap, sync::Arc}; use anyhow::bail; use c509_certificate::c509::C509; +use cip19_shelley_addr::Cip19ShelleyAddrs; use pallas::{ codec::utils::Bytes, crypto::hash::Hash, ledger::traverse::MultiEraTx, network::miniprotocols::Point, @@ -42,7 +44,7 @@ impl RegistrationChain { /// /// # Arguments /// - `cip509` - The CIP509. - /// - `tracking_payment_keys` - The list of payment keys to track. + /// - `tracking_payment_keys` - The list of Shelley keys to track. /// - `point` - The point (slot) of the transaction. /// - `tx_idx` - The transaction index. /// - `txn` - The transaction. @@ -51,7 +53,7 @@ impl RegistrationChain { /// /// Returns an error if data is invalid pub fn new( - &self, point: Point, tracking_payment_keys: Vec, tx_idx: usize, + point: Point, tracking_payment_keys: Vec, tx_idx: usize, txn: &MultiEraTx, cip509: Cip509, ) -> anyhow::Result { let inner = RegistrationChainInner::new(cip509, tracking_payment_keys, point, tx_idx, txn)?; @@ -124,15 +126,15 @@ impl RegistrationChain { &self.inner.role_data } - /// Get the list of payment keys to track. + /// Get the list of Shelley keys to track. #[must_use] - pub fn tracking_payment_keys(&self) -> &Vec { + pub fn tracking_payment_keys(&self) -> &Vec { &self.inner.tracking_payment_keys } - /// Get the map of payment key to its history. + /// Get the map of tracked Shelley keys to its history. #[must_use] - pub fn payment_history(&self) -> &HashMap> { + pub fn payment_history(&self) -> &HashMap> { &self.inner.payment_history } } @@ -159,9 +161,9 @@ struct RegistrationChainInner { /// Map of role number to point, transaction index, and role data. role_data: HashMap, /// List of payment keys to track. - tracking_payment_keys: Arc>, + tracking_payment_keys: Arc>, /// Map of payment key to its history. - payment_history: HashMap>, + payment_history: HashMap>, } impl RegistrationChainInner { @@ -170,7 +172,7 @@ impl RegistrationChainInner { /// /// # Arguments /// - `cip509` - The CIP509. - /// - `tracking_payment_keys` - The list of payment keys to track. + /// - `tracking_payment_keys` - The list of Shelley keys to track. /// - `point` - The point (slot) of the transaction. /// - `tx_idx` - The transaction index. /// - `txn` - The transaction. @@ -179,7 +181,7 @@ impl RegistrationChainInner { /// /// Returns an error if data is invalid fn new( - cip509: Cip509, tracking_payment_keys: Vec, point: Point, tx_idx: usize, + cip509: Cip509, tracking_payment_keys: Vec, point: Point, tx_idx: usize, txn: &MultiEraTx, ) -> anyhow::Result { // Should be chain root, return immediately if not @@ -189,7 +191,7 @@ impl RegistrationChainInner { let mut validation_report = Vec::new(); // Do the CIP509 validation, ensuring the basic validation pass. - if !cip509.validate(txn, tx_idx, &mut validation_report) { + if !cip509.validate(txn, &mut validation_report) { // Log out the error if any error!("CIP509 validation failed: {:?}", validation_report); bail!("CIP509 validation failed, {:?}", validation_report); @@ -245,7 +247,7 @@ impl RegistrationChainInner { let mut validation_report = Vec::new(); // Do the CIP509 validation, ensuring the basic validation pass. - if !cip509.validate(txn, tx_idx, &mut validation_report) { + if !cip509.validate(txn, &mut validation_report) { error!("CIP509 validation failed: {:?}", validation_report); bail!("CIP509 validation failed, {:?}", validation_report); } @@ -448,7 +450,7 @@ fn chain_root_role_data( let encryption_key = role_data.role_encryption_key.clone(); // Get the payment key - let payment_key = get_payment_key_from_tx(txn, role_data.payment_key)?; + let payment_key = get_shelley_addr_from_tx(txn, role_data.payment_key)?; // Map of role number to point and role data role_data_map.insert( @@ -496,7 +498,7 @@ fn update_role_data( } }, }; - let payment_key = get_payment_key_from_tx(txn, role_data.payment_key)?; + let payment_key = get_shelley_addr_from_tx(txn, role_data.payment_key)?; // Map of role number to point and role data // Note that new role data will overwrite the old one @@ -517,10 +519,10 @@ fn update_role_data( Ok(()) } -/// Helper function for retrieving the payment key from the transaction. -fn get_payment_key_from_tx( +/// Helper function for retrieving the Shelley address from the transaction. +fn get_shelley_addr_from_tx( txn: &MultiEraTx, payment_key_ref: Option, -) -> anyhow::Result { +) -> anyhow::Result { // The index should exist since it pass the basic validation if let Some(key_ref) = payment_key_ref { if let MultiEraTx::Conway(tx) = txn { @@ -533,11 +535,11 @@ fn get_payment_key_from_tx( pallas::ledger::primitives::conway::PseudoTransactionOutput::PostAlonzo( o, ) => { - let payment_key: Ed25519PublicKey = + let shelley_addr: Cip19ShelleyAddrs = o.address.clone().try_into().map_err(|_| { - anyhow::anyhow!("Failed to convert Vec to Ed25519PublicKey in payment key reference") + anyhow::anyhow!("Failed to convert Vec to Cip19ShelleyAddrs in payment key reference") })?; - return Ok(payment_key); + return Ok(shelley_addr); }, // Not support legacy form of transaction output pallas::ledger::primitives::conway::PseudoTransactionOutput::Legacy(_) => { @@ -552,12 +554,12 @@ fn get_payment_key_from_tx( bail!("Unsupported payment key reference to transaction input"); } } - Ok(Ed25519PublicKey::default()) + Ok(Cip19ShelleyAddrs::default()) } /// Update the payment history given the tracking payment keys. fn update_payment_history( - tracking_key: &Ed25519PublicKey, txn: &MultiEraTx, point_tx_idx: &PointTxIdx, + tracking_key: &Cip19ShelleyAddrs, txn: &MultiEraTx, point_tx_idx: &PointTxIdx, ) -> anyhow::Result> { let mut payment_history = Vec::new(); if let MultiEraTx::Conway(tx) = txn { @@ -587,3 +589,98 @@ fn update_payment_history( } Ok(payment_history) } + +#[cfg(test)] +mod test { + use minicbor::{Decode, Decoder}; + use pallas::{ledger::traverse::MultiEraTx, network::miniprotocols::Point}; + + use super::RegistrationChain; + use crate::cardano::{cip509::Cip509, transaction::raw_aux_data::RawAuxData}; + + fn cip_509_aux_data(tx: &MultiEraTx<'_>) -> Vec { + let raw_auxiliary_data = tx + .as_conway() + .unwrap() + .clone() + .auxiliary_data + .map(|aux| aux.raw_cbor()); + + let raw_cbor_data = match raw_auxiliary_data { + pallas::codec::utils::Nullable::Some(data) => Ok(data), + _ => Err("Auxiliary data not found"), + }; + + let auxiliary_data = RawAuxData::new(raw_cbor_data.expect("Failed to get raw cbor data")); + auxiliary_data + .get_metadata(509) + .expect("Failed to get metadata") + .to_vec() + } + + fn conway_1() -> Vec { + hex::decode(include_str!("../../test_data/cardano/conway_1.block")) + .expect("Failed to decode hex block.") + } + + fn conway_4() -> Vec { + hex::decode(include_str!("../../test_data/cardano/conway_4.block")) + .expect("Failed to decode hex block.") + } + + #[test] + fn test_new_and_update_registration() { + let conway_block_data_1 = conway_1(); + let point_1 = Point::new( + 77_429_134, + hex::decode("62483f96613b4c48acd28de482eb735522ac180df61766bdb476a7bf83e7bb98") + .unwrap(), + ); + let multi_era_block_1 = + pallas::ledger::traverse::MultiEraBlock::decode(&conway_block_data_1) + .expect("Failed to decode MultiEraBlock"); + + let transactions_1 = multi_era_block_1.txs(); + // Forth transaction of this test data contains the CIP509 auxiliary data + let tx_1 = transactions_1 + .get(3) + .expect("Failed to get transaction index"); + + let aux_data_1 = cip_509_aux_data(tx_1); + let mut decoder = Decoder::new(aux_data_1.as_slice()); + let cip509_1 = Cip509::decode(&mut decoder, &mut ()).expect("Failed to decode Cip509"); + let tracking_payment_keys = vec![]; + + let registration_chain = + RegistrationChain::new(point_1.clone(), tracking_payment_keys, 3, tx_1, cip509_1); + // Able to add chain root to the registration chain + assert!(registration_chain.is_ok()); + + let conway_block_data_4 = conway_4(); + let point_4 = Point::new( + 77_436_369, + hex::decode("b174fc697126f05046b847d47e60d66cbedaf25240027f9c07f27150889aac24") + .unwrap(), + ); + + let multi_era_block_4 = + pallas::ledger::traverse::MultiEraBlock::decode(&conway_block_data_4) + .expect("Failed to decode MultiEraBlock"); + + let transactions_4 = multi_era_block_4.txs(); + // Second transaction of this test data contains the CIP509 auxiliary data + let tx = transactions_4 + .get(1) + .expect("Failed to get transaction index"); + + let aux_data_4 = cip_509_aux_data(tx); + let mut decoder = Decoder::new(aux_data_4.as_slice()); + let cip509 = Cip509::decode(&mut decoder, &mut ()).expect("Failed to decode Cip509"); + + // Update the registration chain + assert!(registration_chain + .unwrap() + .update(point_4.clone(), 1, tx, cip509) + .is_ok()); + } +} diff --git a/rust/rbac-registration/src/registration/cardano/role_data.rs b/rust/rbac-registration/src/registration/cardano/role_data.rs index 684671415e..2432e5656b 100644 --- a/rust/rbac-registration/src/registration/cardano/role_data.rs +++ b/rust/rbac-registration/src/registration/cardano/role_data.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; -use crate::cardano::cip509::rbac::{pub_key::Ed25519PublicKey, role_data::KeyLocalRef}; +use super::cip19_shelley_addr::Cip19ShelleyAddrs; +use crate::cardano::cip509::rbac::role_data::KeyLocalRef; /// Role data #[derive(Clone)] @@ -11,8 +12,8 @@ pub struct RoleData { signing_key_ref: Option, /// An encryption keys to the data within registration. encryption_ref: Option, - /// A payment key where reward will be distributed to. - payment_key: Ed25519PublicKey, + /// A payment key (Shelley address) where reward will be distributed to. + payment_key: Cip19ShelleyAddrs, /// Map of role extended data (10-99) to its data role_extended_data: HashMap>, } @@ -21,7 +22,7 @@ impl RoleData { /// Create an instance of role data. pub(crate) fn new( signing_key_ref: Option, encryption_ref: Option, - payment_key: Ed25519PublicKey, role_extended_data: HashMap>, + payment_key: Cip19ShelleyAddrs, role_extended_data: HashMap>, ) -> Self { RoleData { signing_key_ref, @@ -45,7 +46,7 @@ impl RoleData { /// Get the payment key. #[must_use] - pub fn payment_key(&self) -> &Ed25519PublicKey { + pub fn payment_key(&self) -> &Cip19ShelleyAddrs { &self.payment_key } diff --git a/rust/rbac-registration/src/test_data/cardano/conway_4.block b/rust/rbac-registration/src/test_data/cardano/conway_4.block new file mode 100644 index 0000000000..b16edd16df --- /dev/null +++ b/rust/rbac-registration/src/test_data/cardano/conway_4.block @@ -0,0 +1 @@ +820785828a1a002cf24d1a049d95d15820a82d38572884fc69c5b1105dd190651e4fc5c821878a1a166b6bca897983b83d58206f281ba212f118ac018aaeb805dda9f6fd54fe28cecafe7bec1347509510797f5820870dca606397b85d2e4ee1e46bdb9b784a092a1ec25cb8146cf4046456ff861c825840c085ebef69c078f6fcfd53a2eb2e209b6bd1a517390c8971f079fe55a4b30c82641385a618acf269bceb2d3c83a4ad6addc8901cc3bb359da7875c672ed5a6a55850758500c16a229759d672f0c5aea206fe924238915de34dfdf54413d438a27c4bdb453a080d1fe6ce0f3427452d20aeb1d1907d034899d19021e951a1badeef442de3f4f1bd4e9a4ce5924870f068a4021911c65820c8fc1a8e30b35038644284be081128c4a7ad8b3c39edbfeea871084b9b3566cb845820b7e792177f506de2a34d1c4099f7a1687ff7af54caa093d85c5755e709f757fd0d190241584095a171db3d0e3808bca5e84970ead6b0a736e1d5a2b5fc8c169c8fab7bc1a5d3d60b0b582fbbc8c23d43b3301c4b3eede3ac5438bddfebe1cc8e5a8d71a94802820a005901c05ae6633913fc08585a1ddf905f10b2cc1134d914f9f656b58e72cad542e53a90ce0cc9c6f0e819f7243431a5416cbc1a3fa67d8ab8c547a09f78c86c20073208dc3b328c9d70a24a912aa4e170b9d6fbe8e55c03b52dc296435c86a358bc3f20e89f4c92748dff2ed24a71b8377b4683851a52cfd023dccaa92239d9e989fe8d1d360529c15417937f60530a085ee82dd4ed5f1bc46d0bcf2ab68d4729063a7a5c5074cdb289655f23954f7eebfd418e3a133bb53cfa0bd5ff544fc9d0599640b46619d3bfc5d9782c98ee86fcaa1efe8503980fd9219db77c3003ed2cee13d85f510f9a3381d442f5314a91c52ccf01cc796b9fb7ea14d046a00c3f96e6ee2ec28896f72808952cda9aec2feb690ecb59c1a729816f602a58b06fbab79977a9e96ff7eed2dd262eb86cee8f35d4bad55be2919413ff5cd8fbab3acc25f608630fa7796debcdae0239aafb45e949053af2523bb112b5f6be5fc4ece0ac55f59783466565dad12d42b76fb3ad45112c25d0f4c0880b88ad0ff87f207538c5c7cb96690633a72de47fd36980846cfba4865e324b7ccf1ca80382a4eedc72caf1a0d828049fbd7b3906877b89980bd2f0ca5ffc229e667d56fd11c1dd6e3c0ba7ed82ab0082825820276df9bb9d245ea87e6def1a995ad919edacc907c6cbf028e0e552b1c53c10df0182582062e4dfcb06b8401ea1c405d6290c6aede934c7a6cd31ae000c2a5dd34961af5b000182a300581d70bdc22da682cd9aceed5fd48914789fc98c94abc79fed8b40cb8c431401821a001e8480a1581cc13ddf298a5d25aff2933695987912b4f1748bdf0df8e4b5d85f2360a14e50524550524f445f4f5241434c4501028201d81856d8799fd8799f1a0bf85ea8ff1b000001938742fe98ff82581d60c0359ebb7d0688d79064bd118c99c8b87b5853e3af59245bb97e84d21b000000011587887e021a0006a164031a049d9933081a049d922c0b5820e33c25b2f65204adbf1a8f29ba4c7157c35f9479346e2d6717e23d6786e8b6340d81825820276df9bb9d245ea87e6def1a995ad919edacc907c6cbf028e0e552b1c53c10df010e81581cc0359ebb7d0688d79064bd118c99c8b87b5853e3af59245bb97e84d20f001082581d60c0359ebb7d0688d79064bd118c99c8b87b5853e3af59245bb97e84d21b000000011541dea2111a004c4b40a600818258206695b9cac9230af5c8ee50747b1ca3c78a854d181c7e5c6c371de01b80274d31000181a200583900eb21979c03eed7207020b2a0b47565b5aafb1a2c3849b59a1fa8e6c5e075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d6473903011b000000024f93e7f8021a000304fd07582091e3a1050ba7f37e9d94938ec94a9d187f24b363374c109e3fcc44fedb5de8b70e81581ce075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d64739030f0082a30081825820ef603099b2579d5ca273dce1f1257c11f054664ba972fd61c008b58a1b2325c1584049e2d6c6a948a7d1398f200213a65cd15ac2dd491e903892aaca6ad487717f3cad6c66e201dd8fd74f69898f77aa3de953e83df61f2822c01a30eb992f58f0060681590bd7590bd401000033232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323233027222232325335333006533357346074607e0022646605a60586ae84004dd69aba135744002607c00206e64a666ae68c0ecc1000044c8c8c848cc00400c008c0b8d5d09aba2002375a6ae84004c0fc0040e0dd50022999ab9a303a303f002132321233001003002357426ae88c0fc00cd5d0981f00101b8890008a99ab9c490103505435001637540086ea8004cc09c8888c8d4014888d40188c88c94cd54cd4ccd54c0d40e0c0a80a4c0ac01ccc0b08004d40048888888888880100e44cd5ce24812d546865207472616e73616374696f6e206973206e6f74207369676e6564206279206f7261636c65206f776e657200030132533553355335333553036039302b02a253335302135001202103e215333573466ebcc118cd5d0182319aba0375000a6ec4080cd5d01ba835500b03937620400022a66a666036446a0044466603e446a00444a666ae68c12c004400c4cc11848ccc00401c00c00800c00c0040c0cd54c0e80ec8d400488cc0e0008cd54c0f40f88d400488cc0ec008ccd4004dc0a4000e048cdc0800a400000266aa607407646a0024466070004666a002466aa607c07e46a0024466078004604600200244666038066004002466aa607c07e46a0024466078004604000200266602e05c666050400204e6a004404e0060784426a004444a66a0082a666ae68cdd78018238a999ab9a3375e00408e2a666ae68cdc4000a400006e2666ae68cdc4800a410125e80206a07006e06e44072064407e6044014074266ae712401024c310003103a1335738921156f757470757420646f6573206e6f74206d6174636800031153355333573466e2400d20001335738921165072696365206d75737420626520706f7369746976650003103a15335533535353301275a6a00407e06e44a666a00442a666ae68cdc419b8000100935500c03a0331333573466e24004d540300e80c40d00c80c84d4cc049d69a80101f911a801112999a99980980a980f19b8100900b0021533500113330120150030081333012015003008034133301201500300803003a13357389212345787069726174696f6e2074696d65206973206e6f742070726f7065726c792073657400031030030333025200102435302635533530270092100116036202402f302d350080393302f3016337000020060542a666a602e6aa66a60320022602602a442a66a0022004442602e032402e02842a66a6666666ae900048c94ccd5cd181d98200008991999aab9f001202d23233335573e002405e46666aae7cd5d1001119299a9999999aba400123253335734608660900022646666aae7c00480d48cccd55cf9aba20022533530203574200642605e00206a406c07a078608e0020646ea800880c880c880c880c80e4854cd4c070d5d08029098159981a8010008188181aba1005203003703635744004068607e0020546ea800880a880a880a880a80c48400405480548c94ccd5cd181b181d800899191919091998008028018011bad357426ae88008dd69aba10013574460760046ae84c0e80040ccdd50009111a801111a801912999a9998040038020010a99a8018800819814819911192999a80190a999a80190a999a80290980200b0980180a8a999a80210980200b0980180a80c0060a999a80210980180a8980100a0a999a80190980180a8980100a00b8a999a801100700b0068a999a80110a999a80210980180a8980100a0a999a80190980180a8980100a00b8058a999a80190980100a098008098a999a80110980100a0980080980b12999a80110a999a80210a999a802109998040038010008b0b0b0060a999a80190a999a801909998038030010008b0b0b00580691a80091111111003891999999980091199ab9a3370e00400204004644a666ae68cdc38010008098a999ab9a3371200400201401044666ae68cdc400100081001191199ab9a3371200400204004644666ae68cdc480100081181011199ab9a3371000400204604044a666ae68cdc480100088008801112999ab9a33712004002200420024464a666ae68c0c8c0dc0044c8c8cc0994ccd5cd181a181c801099813198038029aba130380023006357426ae88c0e00080c54ccd5cd181a181c800899813198038029aba130380013006357426ae88c0e00040c4dd51aba135744606e0046ea8d5d0981b0008179baa0012325333573460620020522a666ae68c0c000407c0b4c0d0dd50009119192999ab9a303300100815333573460640022601460086ae84c0d400854ccd5cd1818800803017181a8009baa00122233355302302702a335530260272350012233024002300b001333553023027223500222533533355302802b301d01c235001223300a002005006100313302e00400301c001335530260272350012233024002330382253350011300a003221350022253353300c002008112223300200a0041300600300400211009212223001004112220012230302253350011003221330060023004001212223003004233333335748002403040304030460206eb4008806007c94cd5ce2481286578706563746564206f6e6c7920612073696e676c6520636f6e74696e75696e67206f7574707574001615335738920117496e76616c696420646174756d20696e206f757470757400164988880088c8c94ccd5cd1813000899091118010021aba13028002153335734604a002264244460020086ae84c0a000854ccd5cd181200080201098140009baa00111003253353007001213335530150192235300535300935003019222200422353007350042222004225333573466ebc01000854ccd5cd19baf0030011330220060051005100500e3300d00735300f3500201b22222222222200a15335738921024c660016232533357346040604a0022646424660020060046ae84d5d118128011aba1302400101d3754002444006660024002eb4888cc09088cccd55cf80090071191980e9980a180398138009803181300098021aba2003357420040306eac0048c94ccd5cd180e181080089919191919190919998008038028018011aba1357440046ae84004d5d10011aba10013574460420046ae84c080004064dd5000919191999aa999ab9a3370e90030008990911118020029aba13020002153335734603c00226424444600400a6ae84c08000854ccd5cd180e8008990911118008029aba13020002153335734603800226424444600600a6ae84c0800080648034803480348ccd54c048054cc03c894cd40088400c400403494ccd5cd19baf002350010181300600100d3300923253335734603e60480022646424660020060046ae84d5d118120011aba1302300101c37540026a60166a00802e44444444444401860400026ea8d40040408488c00800c48cc004894cd400804c40040208cc02488ccd400c04c008004d400403488ccd5cd19baf002001004007223301c2233335573e002400c466028600a6ae84008c00cd5d10010081bac001100d23253335734602860320022646464646464646464646464646464646464646464642466666666666600202e02a02602201e01a01601200e00a0060046ae84d5d10011aba1001357440046ae84004d5d10011aba1001357440046ae84004d5d10011aba1001357440046ae84004d5d10011aba1001357440046ae84004d5d10011aba1001357440046ae84004d5d1180c8011aba1301800101137540022002200c464a666ae68c044c0580044dd69aba1301500100e37540024424660020060044446006600400260244422444a66a00220044426600a004666aa600e01600a00800260224422444a66a00226a00600c442666a00a0186008004666aa600e01400a00800244002601e442244a66a00200c44266014600800466aa600c00e00800224002220024400444244660020080062a66ae712411f496e76616c696420646174756d20746f20636865636b4f776e4f757470757400161533573892010350543100162222222222220054c1014000370e90001b8748008dc3a40086e9520005573caae748c8c00400488cc00cc00800800530012cd8799f581cc0359ebb7d0688d79064bd118c99c8b87b5853e3af59245bb97e84d21a000dbba01a01499700ff00010581840001d8799f1b0000019385f96798d8799f1a0bf85ea8ffff821a001862581a18087eb7a100828258208469288efa6f9cb49040b43dcff93f40969d72433f751afde50235012c01602058404ac843657462bd1b0f2db7e1abfa2fa3ccd3105ad2278649e155ceb3cf4e44b3cc2532815570cee26a55910a04db4de50cd3c07784ecfacf4c74706f54cd470382582076af5530fa318a370820270031d1838545a4ceed8696510627563d1114d4182b5840c9fe85cdcef2b32d76958d564be1b7bc0124a99594cc9e69e1a4d0cbe8f96eed4ca94fe6f2471382d19d74f610a6a5e01e56d8f6dc2a5519a090ec2e00dc3e05a101a11901fda50050ca7a1457ef9f4c7f9c747f8c4a4cfa6c01505be7b97fa11335b727bbf095a3f0fb7c0258206695b9cac9230af5c8ee50747b1ca3c78a854d181c7e5c6c371de01b80274d310b8758401b3e020864c84e53c9f7a9c54b8d09c6047bc2049aed7438c5575ed4ee265182dd808a52ae8b12083cb540fa9ccc7e0ec3a7b52ad5f134682286f658ff0083f558400dc73df538d858d8d8b89e5247f2000f1f47c43b0c68204480001fc71a179f0685400804400c2484e3013b03195a0a79c94206484bc93b10cbcb474999a5e5a55840b17f9619347e158e3a2a44e3e33eb72d648ae645a0e63d83fde739ee0d7ff6baeaf5767357770a697c2a92095bfe292e427bbc2fee56211ec78389dfa56d13c758400363abd573e840dead26d80c600380b5bc64a3c285550096634883e3a7265b4f18ca836d1d23b991a02a45ac365c9665acb787484da6ee21a10a1212ee5e5e11584012912b55d77a3e82444744ca4581c84877c958f9583f7910e4251d15161126e91b1d11e72525271b11e5870e0f0a0f94f18e080908f7f4f6918af68de8fc1bdd5840ec35fc967e64936c930f279eb8d043d31112e6a71aaaa76fc3455e9d30b90ea671971e5c9ecd4be5b4d87ab3e11f7de3b8984ea353e9a2d8d65c6ad6f9102c46581876789c8667c739c00da3176c46a1b030c4281c4e62afcf3a186358401824797b7e12054dabb6fef573ceba9c3bbed87b522a4141c2357d05d63ffabee59add33aac71f4573e43520a1c000d0c4e7fa2adf7f8e92718320527d23e60580 \ No newline at end of file From 3f913e9188ae5dcd221403c9f5c8b2779ce6887b Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 2 Dec 2024 14:17:55 +0700 Subject: [PATCH 2/6] chore: comment --- .../src/registration/cardano/cip19_shelley_addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs b/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs index 5717e07a8b..680716e408 100644 --- a/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs +++ b/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs @@ -12,7 +12,7 @@ use pallas::codec::utils::Bytes; -/// CIP-0019 Shelley Addresses (only support type 0 - 5) +/// CIP-0019 Shelley Addresses (only support type 0 - 3) #[derive(PartialEq, Clone, Eq, Hash)] pub struct Cip19ShelleyAddrs([u8; 57]); From 8995c3a6e1c7fc9d91f6910bdc2e8bcfc7e4e29a Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 2 Dec 2024 14:26:10 +0700 Subject: [PATCH 3/6] fix: format --- .../src/registration/cardano/mod.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/rust/rbac-registration/src/registration/cardano/mod.rs b/rust/rbac-registration/src/registration/cardano/mod.rs index ac5ba711fa..a6cbb0b1b9 100644 --- a/rust/rbac-registration/src/registration/cardano/mod.rs +++ b/rust/rbac-registration/src/registration/cardano/mod.rs @@ -480,18 +480,22 @@ fn update_role_data( // If there is new role singing key, use it, else use the old one let signing_key = match role_data.role_signing_key { Some(key) => Some(key), - None => match inner.role_data.get(&role_data.role_number) { - Some((_, role_data)) => role_data.signing_key_ref().clone(), - None => None, + None => { + match inner.role_data.get(&role_data.role_number) { + Some((_, role_data)) => role_data.signing_key_ref().clone(), + None => None, + } }, }; // If there is new role encryption key, use it, else use the old one let encryption_key = match role_data.role_encryption_key { Some(key) => Some(key), - None => match inner.role_data.get(&role_data.role_number) { - Some((_, role_data)) => role_data.encryption_ref().clone(), - None => None, + None => { + match inner.role_data.get(&role_data.role_number) { + Some((_, role_data)) => role_data.encryption_ref().clone(), + None => None, + } }, }; let payment_key = get_shelley_addr_from_tx(txn, role_data.payment_key)?; From 85320da5a67eb2e36806c102865783fe797004e0 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 2 Dec 2024 18:20:04 +0700 Subject: [PATCH 4/6] fix: use ShelleyPaymentPart Signed-off-by: bkioshn --- .../cardano/cip19_shelley_addr.rs | 54 ---------------- .../src/registration/cardano/mod.rs | 64 +++++++++++-------- .../src/registration/cardano/role_data.rs | 11 ++-- 3 files changed, 43 insertions(+), 86 deletions(-) delete mode 100644 rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs diff --git a/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs b/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs deleted file mode 100644 index 680716e408..0000000000 --- a/rust/rbac-registration/src/registration/cardano/cip19_shelley_addr.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! CIP-0019 Shelley Addresses -//! there are currently 8 types of Shelley addresses -//! Header type Payment Part Delegation Part -//! (0) `PaymentKeyHash` `StakeKeyHash` -//! (1) `ScriptHash` `StakeKeyHash` -//! (2) `PaymentKeyHash` `ScriptHash` -//! (3) `ScriptHash` `ScriptHash` -//! (4) `PaymentKeyHash` `Pointer` -//! (5) `ScriptHash` `Pointer` -//! (6) `PaymentKeyHash` ø -//! (7) `ScriptHash` ø - -use pallas::codec::utils::Bytes; - -/// CIP-0019 Shelley Addresses (only support type 0 - 3) -#[derive(PartialEq, Clone, Eq, Hash)] -pub struct Cip19ShelleyAddrs([u8; 57]); - -impl From<[u8; 57]> for Cip19ShelleyAddrs { - fn from(bytes: [u8; 57]) -> Self { - Cip19ShelleyAddrs(bytes) - } -} - -impl Default for Cip19ShelleyAddrs { - fn default() -> Self { - Self([0; 57]) - } -} - -impl TryFrom for Cip19ShelleyAddrs { - type Error = &'static str; - - fn try_from(bytes: Bytes) -> Result { - let byte_vec: Vec = bytes.into(); - - if byte_vec.len() != 57 { - return Err("Invalid length for Ed25519 public key: expected 57 bytes."); - } - - let byte_array: [u8; 57] = byte_vec - .try_into() - .map_err(|_| "Failed to convert Vec to [u8; 32]")?; - - Ok(Cip19ShelleyAddrs::from(byte_array)) - } -} - -impl From for Bytes { - fn from(val: Cip19ShelleyAddrs) -> Self { - let vec: Vec = val.0.to_vec(); - Bytes::from(vec) - } -} diff --git a/rust/rbac-registration/src/registration/cardano/mod.rs b/rust/rbac-registration/src/registration/cardano/mod.rs index a6cbb0b1b9..dd27ade903 100644 --- a/rust/rbac-registration/src/registration/cardano/mod.rs +++ b/rust/rbac-registration/src/registration/cardano/mod.rs @@ -1,6 +1,5 @@ //! Chain of Cardano registration data -pub mod cip19_shelley_addr; pub mod payment_history; pub mod point_tx_idx; pub mod role_data; @@ -9,9 +8,12 @@ use std::{collections::HashMap, sync::Arc}; use anyhow::bail; use c509_certificate::c509::C509; -use cip19_shelley_addr::Cip19ShelleyAddrs; use pallas::{ - codec::utils::Bytes, crypto::hash::Hash, ledger::traverse::MultiEraTx, + crypto::hash::Hash, + ledger::{ + addresses::{Address, ShelleyPaymentPart}, + traverse::MultiEraTx, + }, network::miniprotocols::Point, }; use payment_history::PaymentHistory; @@ -44,7 +46,7 @@ impl RegistrationChain { /// /// # Arguments /// - `cip509` - The CIP509. - /// - `tracking_payment_keys` - The list of Shelley keys to track. + /// - `tracking_payment_keys` - The list of payment keys to track. /// - `point` - The point (slot) of the transaction. /// - `tx_idx` - The transaction index. /// - `txn` - The transaction. @@ -53,7 +55,7 @@ impl RegistrationChain { /// /// Returns an error if data is invalid pub fn new( - point: Point, tracking_payment_keys: Vec, tx_idx: usize, + point: Point, tracking_payment_keys: Vec, tx_idx: usize, txn: &MultiEraTx, cip509: Cip509, ) -> anyhow::Result { let inner = RegistrationChainInner::new(cip509, tracking_payment_keys, point, tx_idx, txn)?; @@ -126,15 +128,15 @@ impl RegistrationChain { &self.inner.role_data } - /// Get the list of Shelley keys to track. + /// Get the list of payment keys to track. #[must_use] - pub fn tracking_payment_keys(&self) -> &Vec { + pub fn tracking_payment_keys(&self) -> &Vec { &self.inner.tracking_payment_keys } - /// Get the map of tracked Shelley keys to its history. + /// Get the map of tracked payment keys to its history. #[must_use] - pub fn payment_history(&self) -> &HashMap> { + pub fn payment_history(&self) -> &HashMap> { &self.inner.payment_history } } @@ -161,9 +163,9 @@ struct RegistrationChainInner { /// Map of role number to point, transaction index, and role data. role_data: HashMap, /// List of payment keys to track. - tracking_payment_keys: Arc>, + tracking_payment_keys: Arc>, /// Map of payment key to its history. - payment_history: HashMap>, + payment_history: HashMap>, } impl RegistrationChainInner { @@ -172,7 +174,7 @@ impl RegistrationChainInner { /// /// # Arguments /// - `cip509` - The CIP509. - /// - `tracking_payment_keys` - The list of Shelley keys to track. + /// - `tracking_payment_keys` - The list of payment keys to track. /// - `point` - The point (slot) of the transaction. /// - `tx_idx` - The transaction index. /// - `txn` - The transaction. @@ -181,8 +183,8 @@ impl RegistrationChainInner { /// /// Returns an error if data is invalid fn new( - cip509: Cip509, tracking_payment_keys: Vec, point: Point, tx_idx: usize, - txn: &MultiEraTx, + cip509: Cip509, tracking_payment_keys: Vec, point: Point, + tx_idx: usize, txn: &MultiEraTx, ) -> anyhow::Result { // Should be chain root, return immediately if not if cip509.prv_tx_id.is_some() { @@ -450,7 +452,7 @@ fn chain_root_role_data( let encryption_key = role_data.role_encryption_key.clone(); // Get the payment key - let payment_key = get_shelley_addr_from_tx(txn, role_data.payment_key)?; + let payment_key = get_payment_addr_from_tx(txn, role_data.payment_key)?; // Map of role number to point and role data role_data_map.insert( @@ -498,7 +500,7 @@ fn update_role_data( } }, }; - let payment_key = get_shelley_addr_from_tx(txn, role_data.payment_key)?; + let payment_key = get_payment_addr_from_tx(txn, role_data.payment_key)?; // Map of role number to point and role data // Note that new role data will overwrite the old one @@ -520,9 +522,9 @@ fn update_role_data( } /// Helper function for retrieving the Shelley address from the transaction. -fn get_shelley_addr_from_tx( +fn get_payment_addr_from_tx( txn: &MultiEraTx, payment_key_ref: Option, -) -> anyhow::Result { +) -> anyhow::Result> { // The index should exist since it pass the basic validation if let Some(key_ref) = payment_key_ref { if let MultiEraTx::Conway(tx) = txn { @@ -535,11 +537,13 @@ fn get_shelley_addr_from_tx( pallas::ledger::primitives::conway::PseudoTransactionOutput::PostAlonzo( o, ) => { - let shelley_addr: Cip19ShelleyAddrs = - o.address.clone().try_into().map_err(|_| { - anyhow::anyhow!("Failed to convert Vec to Cip19ShelleyAddrs in payment key reference") - })?; - return Ok(shelley_addr); + let address = + Address::from_bytes(&o.address).map_err(|e| anyhow::anyhow!(e))?; + + if let Address::Shelley(addr) = address { + return Ok(Some(addr.payment().clone())); + } + bail!("Unsupported address type in payment key reference"); }, // Not support legacy form of transaction output pallas::ledger::primitives::conway::PseudoTransactionOutput::Legacy(_) => { @@ -554,12 +558,12 @@ fn get_shelley_addr_from_tx( bail!("Unsupported payment key reference to transaction input"); } } - Ok(Cip19ShelleyAddrs::default()) + Ok(None) } /// Update the payment history given the tracking payment keys. fn update_payment_history( - tracking_key: &Cip19ShelleyAddrs, txn: &MultiEraTx, point_tx_idx: &PointTxIdx, + tracking_key: &ShelleyPaymentPart, txn: &MultiEraTx, point_tx_idx: &PointTxIdx, ) -> anyhow::Result> { let mut payment_history = Vec::new(); if let MultiEraTx::Conway(tx) = txn { @@ -567,8 +571,14 @@ fn update_payment_history( for (index, output) in tx.transaction_body.outputs.iter().enumerate() { match output { pallas::ledger::primitives::conway::PseudoTransactionOutput::PostAlonzo(o) => { - let address_bytes: Bytes = tracking_key.clone().into(); - if address_bytes == o.address { + let address = + Address::from_bytes(&o.address).map_err(|e| anyhow::anyhow!(e))?; + let shelley_payment = if let Address::Shelley(addr) = address { + addr.payment().clone() + } else { + bail!("Unsupported address type in update payment history"); + }; + if tracking_key == &shelley_payment { let output_index: u16 = index.try_into().map_err(|_| { anyhow::anyhow!("Cannot convert usize to u16 in update payment history") })?; diff --git a/rust/rbac-registration/src/registration/cardano/role_data.rs b/rust/rbac-registration/src/registration/cardano/role_data.rs index 2432e5656b..b6b4d947d7 100644 --- a/rust/rbac-registration/src/registration/cardano/role_data.rs +++ b/rust/rbac-registration/src/registration/cardano/role_data.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; -use super::cip19_shelley_addr::Cip19ShelleyAddrs; +use pallas::ledger::addresses::ShelleyPaymentPart; + use crate::cardano::cip509::rbac::role_data::KeyLocalRef; /// Role data @@ -12,8 +13,8 @@ pub struct RoleData { signing_key_ref: Option, /// An encryption keys to the data within registration. encryption_ref: Option, - /// A payment key (Shelley address) where reward will be distributed to. - payment_key: Cip19ShelleyAddrs, + /// A payment key where reward will be distributed to. + payment_key: Option, /// Map of role extended data (10-99) to its data role_extended_data: HashMap>, } @@ -22,7 +23,7 @@ impl RoleData { /// Create an instance of role data. pub(crate) fn new( signing_key_ref: Option, encryption_ref: Option, - payment_key: Cip19ShelleyAddrs, role_extended_data: HashMap>, + payment_key: Option, role_extended_data: HashMap>, ) -> Self { RoleData { signing_key_ref, @@ -46,7 +47,7 @@ impl RoleData { /// Get the payment key. #[must_use] - pub fn payment_key(&self) -> &Cip19ShelleyAddrs { + pub fn payment_key(&self) -> &Option { &self.payment_key } From ef6c9365425fe023363bd0ee1555e6d16fe044e7 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 2 Dec 2024 18:58:17 +0700 Subject: [PATCH 5/6] fix: track ShelleyAddress Signed-off-by: bkioshn --- .../src/registration/cardano/mod.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/rust/rbac-registration/src/registration/cardano/mod.rs b/rust/rbac-registration/src/registration/cardano/mod.rs index dd27ade903..e3e1fd6178 100644 --- a/rust/rbac-registration/src/registration/cardano/mod.rs +++ b/rust/rbac-registration/src/registration/cardano/mod.rs @@ -11,7 +11,7 @@ use c509_certificate::c509::C509; use pallas::{ crypto::hash::Hash, ledger::{ - addresses::{Address, ShelleyPaymentPart}, + addresses::{Address, ShelleyAddress, ShelleyPaymentPart}, traverse::MultiEraTx, }, network::miniprotocols::Point, @@ -55,8 +55,8 @@ impl RegistrationChain { /// /// Returns an error if data is invalid pub fn new( - point: Point, tracking_payment_keys: Vec, tx_idx: usize, - txn: &MultiEraTx, cip509: Cip509, + point: Point, tracking_payment_keys: Vec, tx_idx: usize, txn: &MultiEraTx, + cip509: Cip509, ) -> anyhow::Result { let inner = RegistrationChainInner::new(cip509, tracking_payment_keys, point, tx_idx, txn)?; @@ -130,13 +130,13 @@ impl RegistrationChain { /// Get the list of payment keys to track. #[must_use] - pub fn tracking_payment_keys(&self) -> &Vec { + pub fn tracking_payment_keys(&self) -> &Vec { &self.inner.tracking_payment_keys } /// Get the map of tracked payment keys to its history. #[must_use] - pub fn payment_history(&self) -> &HashMap> { + pub fn payment_history(&self) -> &HashMap> { &self.inner.payment_history } } @@ -163,9 +163,9 @@ struct RegistrationChainInner { /// Map of role number to point, transaction index, and role data. role_data: HashMap, /// List of payment keys to track. - tracking_payment_keys: Arc>, + tracking_payment_keys: Arc>, /// Map of payment key to its history. - payment_history: HashMap>, + payment_history: HashMap>, } impl RegistrationChainInner { @@ -183,8 +183,8 @@ impl RegistrationChainInner { /// /// Returns an error if data is invalid fn new( - cip509: Cip509, tracking_payment_keys: Vec, point: Point, - tx_idx: usize, txn: &MultiEraTx, + cip509: Cip509, tracking_payment_keys: Vec, point: Point, tx_idx: usize, + txn: &MultiEraTx, ) -> anyhow::Result { // Should be chain root, return immediately if not if cip509.prv_tx_id.is_some() { @@ -563,7 +563,7 @@ fn get_payment_addr_from_tx( /// Update the payment history given the tracking payment keys. fn update_payment_history( - tracking_key: &ShelleyPaymentPart, txn: &MultiEraTx, point_tx_idx: &PointTxIdx, + tracking_key: &ShelleyAddress, txn: &MultiEraTx, point_tx_idx: &PointTxIdx, ) -> anyhow::Result> { let mut payment_history = Vec::new(); if let MultiEraTx::Conway(tx) = txn { @@ -574,7 +574,7 @@ fn update_payment_history( let address = Address::from_bytes(&o.address).map_err(|e| anyhow::anyhow!(e))?; let shelley_payment = if let Address::Shelley(addr) = address { - addr.payment().clone() + addr.clone() } else { bail!("Unsupported address type in update payment history"); }; From 6cec7d6db04fb23b54faf871bee31968de7f9e7e Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 2 Dec 2024 20:57:44 +0700 Subject: [PATCH 6/6] fix: remove tracking_payment_key and use tracking_payment_history Signed-off-by: bkioshn --- .../src/registration/cardano/mod.rs | 67 ++++++++----------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/rust/rbac-registration/src/registration/cardano/mod.rs b/rust/rbac-registration/src/registration/cardano/mod.rs index e3e1fd6178..3895d8971b 100644 --- a/rust/rbac-registration/src/registration/cardano/mod.rs +++ b/rust/rbac-registration/src/registration/cardano/mod.rs @@ -55,7 +55,7 @@ impl RegistrationChain { /// /// Returns an error if data is invalid pub fn new( - point: Point, tracking_payment_keys: Vec, tx_idx: usize, txn: &MultiEraTx, + point: Point, tracking_payment_keys: &[ShelleyAddress], tx_idx: usize, txn: &MultiEraTx, cip509: Cip509, ) -> anyhow::Result { let inner = RegistrationChainInner::new(cip509, tracking_payment_keys, point, tx_idx, txn)?; @@ -128,16 +128,10 @@ impl RegistrationChain { &self.inner.role_data } - /// Get the list of payment keys to track. - #[must_use] - pub fn tracking_payment_keys(&self) -> &Vec { - &self.inner.tracking_payment_keys - } - /// Get the map of tracked payment keys to its history. #[must_use] - pub fn payment_history(&self) -> &HashMap> { - &self.inner.payment_history + pub fn tracking_payment_history(&self) -> &HashMap> { + &self.inner.tracking_payment_history } } @@ -162,10 +156,8 @@ struct RegistrationChainInner { // Role /// Map of role number to point, transaction index, and role data. role_data: HashMap, - /// List of payment keys to track. - tracking_payment_keys: Arc>, - /// Map of payment key to its history. - payment_history: HashMap>, + /// Map of tracked payment key to its history. + tracking_payment_history: HashMap>, } impl RegistrationChainInner { @@ -183,7 +175,7 @@ impl RegistrationChainInner { /// /// Returns an error if data is invalid fn new( - cip509: Cip509, tracking_payment_keys: Vec, point: Point, tx_idx: usize, + cip509: Cip509, tracking_payment_keys: &[ShelleyAddress], point: Point, tx_idx: usize, txn: &MultiEraTx, ) -> anyhow::Result { // Should be chain root, return immediately if not @@ -211,12 +203,13 @@ impl RegistrationChainInner { let revocations = revocations_list(registration.revocation_list, &point_tx_idx); let role_data_map = chain_root_role_data(registration.role_set, txn, &point_tx_idx)?; - let mut payment_history = HashMap::new(); - for tracking_key in &tracking_payment_keys { - // Keep record of payment history, the payment key that we want to track - let histories = update_payment_history(tracking_key, txn, &point_tx_idx)?; - payment_history.insert(tracking_key.clone(), histories); + let mut tracking_payment_history = HashMap::new(); + // Create a payment history for each tracking payment key + for tracking_key in tracking_payment_keys { + tracking_payment_history.insert(tracking_key.clone(), Vec::new()); } + // Keep record of payment history, the payment key that we want to track + update_tracking_payment_history(&mut tracking_payment_history, txn, &point_tx_idx)?; Ok(Self { purpose, @@ -226,8 +219,7 @@ impl RegistrationChainInner { simple_keys: public_key_map, revocations, role_data: role_data_map, - tracking_payment_keys: Arc::new(tracking_payment_keys), - payment_history, + tracking_payment_history, }) } @@ -284,16 +276,11 @@ impl RegistrationChainInner { update_role_data(&mut new_inner, registration.role_set, txn, &point_tx_idx)?; - for tracking_key in self.tracking_payment_keys.iter() { - let histories = update_payment_history(tracking_key, txn, &point_tx_idx)?; - // If tracking payment key doesn't exist, insert an empty vector, - // then add the histories to the history vector - new_inner - .payment_history - .entry(tracking_key.clone()) - .or_default() - .extend(histories); - } + update_tracking_payment_history( + &mut new_inner.tracking_payment_history, + txn, + &point_tx_idx, + )?; Ok(new_inner) } @@ -562,10 +549,10 @@ fn get_payment_addr_from_tx( } /// Update the payment history given the tracking payment keys. -fn update_payment_history( - tracking_key: &ShelleyAddress, txn: &MultiEraTx, point_tx_idx: &PointTxIdx, -) -> anyhow::Result> { - let mut payment_history = Vec::new(); +fn update_tracking_payment_history( + tracking_payment_history: &mut HashMap>, txn: &MultiEraTx, + point_tx_idx: &PointTxIdx, +) -> anyhow::Result<()> { if let MultiEraTx::Conway(tx) = txn { // Conway era -> Post alonzo tx output for (index, output) in tx.transaction_body.outputs.iter().enumerate() { @@ -578,12 +565,14 @@ fn update_payment_history( } else { bail!("Unsupported address type in update payment history"); }; - if tracking_key == &shelley_payment { + // If the payment key from the output exist in the payment history, add the + // history + if let Some(vec) = tracking_payment_history.get_mut(&shelley_payment) { let output_index: u16 = index.try_into().map_err(|_| { anyhow::anyhow!("Cannot convert usize to u16 in update payment history") })?; - payment_history.push(PaymentHistory::new( + vec.push(PaymentHistory::new( point_tx_idx.clone(), txn.hash(), output_index, @@ -597,7 +586,7 @@ fn update_payment_history( } } } - Ok(payment_history) + Ok(()) } #[cfg(test)] @@ -662,7 +651,7 @@ mod test { let tracking_payment_keys = vec![]; let registration_chain = - RegistrationChain::new(point_1.clone(), tracking_payment_keys, 3, tx_1, cip509_1); + RegistrationChain::new(point_1.clone(), &tracking_payment_keys, 3, tx_1, cip509_1); // Able to add chain root to the registration chain assert!(registration_chain.is_ok());