11//! Chain of Cardano registration data
22
3+ pub mod cip19_shelley_addr;
34pub mod payment_history;
45pub mod point_tx_idx;
56pub mod role_data;
@@ -8,6 +9,7 @@ use std::{collections::HashMap, sync::Arc};
89
910use anyhow:: bail;
1011use c509_certificate:: c509:: C509 ;
12+ use cip19_shelley_addr:: Cip19ShelleyAddrs ;
1113use pallas:: {
1214 codec:: utils:: Bytes , crypto:: hash:: Hash , ledger:: traverse:: MultiEraTx ,
1315 network:: miniprotocols:: Point ,
@@ -42,7 +44,7 @@ impl RegistrationChain {
4244 ///
4345 /// # Arguments
4446 /// - `cip509` - The CIP509.
45- /// - `tracking_payment_keys` - The list of payment keys to track.
47+ /// - `tracking_payment_keys` - The list of Shelley keys to track.
4648 /// - `point` - The point (slot) of the transaction.
4749 /// - `tx_idx` - The transaction index.
4850 /// - `txn` - The transaction.
@@ -51,7 +53,7 @@ impl RegistrationChain {
5153 ///
5254 /// Returns an error if data is invalid
5355 pub fn new (
54- & self , point : Point , tracking_payment_keys : Vec < Ed25519PublicKey > , tx_idx : usize ,
56+ point : Point , tracking_payment_keys : Vec < Cip19ShelleyAddrs > , tx_idx : usize ,
5557 txn : & MultiEraTx , cip509 : Cip509 ,
5658 ) -> anyhow:: Result < Self > {
5759 let inner = RegistrationChainInner :: new ( cip509, tracking_payment_keys, point, tx_idx, txn) ?;
@@ -124,15 +126,15 @@ impl RegistrationChain {
124126 & self . inner . role_data
125127 }
126128
127- /// Get the list of payment keys to track.
129+ /// Get the list of Shelley keys to track.
128130 #[ must_use]
129- pub fn tracking_payment_keys ( & self ) -> & Vec < Ed25519PublicKey > {
131+ pub fn tracking_payment_keys ( & self ) -> & Vec < Cip19ShelleyAddrs > {
130132 & self . inner . tracking_payment_keys
131133 }
132134
133- /// Get the map of payment key to its history.
135+ /// Get the map of tracked Shelley keys to its history.
134136 #[ must_use]
135- pub fn payment_history ( & self ) -> & HashMap < Ed25519PublicKey , Vec < PaymentHistory > > {
137+ pub fn payment_history ( & self ) -> & HashMap < Cip19ShelleyAddrs , Vec < PaymentHistory > > {
136138 & self . inner . payment_history
137139 }
138140}
@@ -159,9 +161,9 @@ struct RegistrationChainInner {
159161 /// Map of role number to point, transaction index, and role data.
160162 role_data : HashMap < u8 , ( PointTxIdx , RoleData ) > ,
161163 /// List of payment keys to track.
162- tracking_payment_keys : Arc < Vec < Ed25519PublicKey > > ,
164+ tracking_payment_keys : Arc < Vec < Cip19ShelleyAddrs > > ,
163165 /// Map of payment key to its history.
164- payment_history : HashMap < Ed25519PublicKey , Vec < PaymentHistory > > ,
166+ payment_history : HashMap < Cip19ShelleyAddrs , Vec < PaymentHistory > > ,
165167}
166168
167169impl RegistrationChainInner {
@@ -170,7 +172,7 @@ impl RegistrationChainInner {
170172 ///
171173 /// # Arguments
172174 /// - `cip509` - The CIP509.
173- /// - `tracking_payment_keys` - The list of payment keys to track.
175+ /// - `tracking_payment_keys` - The list of Shelley keys to track.
174176 /// - `point` - The point (slot) of the transaction.
175177 /// - `tx_idx` - The transaction index.
176178 /// - `txn` - The transaction.
@@ -179,7 +181,7 @@ impl RegistrationChainInner {
179181 ///
180182 /// Returns an error if data is invalid
181183 fn new (
182- cip509 : Cip509 , tracking_payment_keys : Vec < Ed25519PublicKey > , point : Point , tx_idx : usize ,
184+ cip509 : Cip509 , tracking_payment_keys : Vec < Cip19ShelleyAddrs > , point : Point , tx_idx : usize ,
183185 txn : & MultiEraTx ,
184186 ) -> anyhow:: Result < Self > {
185187 // Should be chain root, return immediately if not
@@ -189,7 +191,7 @@ impl RegistrationChainInner {
189191
190192 let mut validation_report = Vec :: new ( ) ;
191193 // Do the CIP509 validation, ensuring the basic validation pass.
192- if !cip509. validate ( txn, tx_idx , & mut validation_report) {
194+ if !cip509. validate ( txn, & mut validation_report) {
193195 // Log out the error if any
194196 error ! ( "CIP509 validation failed: {:?}" , validation_report) ;
195197 bail ! ( "CIP509 validation failed, {:?}" , validation_report) ;
@@ -245,7 +247,7 @@ impl RegistrationChainInner {
245247
246248 let mut validation_report = Vec :: new ( ) ;
247249 // Do the CIP509 validation, ensuring the basic validation pass.
248- if !cip509. validate ( txn, tx_idx , & mut validation_report) {
250+ if !cip509. validate ( txn, & mut validation_report) {
249251 error ! ( "CIP509 validation failed: {:?}" , validation_report) ;
250252 bail ! ( "CIP509 validation failed, {:?}" , validation_report) ;
251253 }
@@ -448,7 +450,7 @@ fn chain_root_role_data(
448450 let encryption_key = role_data. role_encryption_key . clone ( ) ;
449451
450452 // Get the payment key
451- let payment_key = get_payment_key_from_tx ( txn, role_data. payment_key ) ?;
453+ let payment_key = get_shelley_addr_from_tx ( txn, role_data. payment_key ) ?;
452454
453455 // Map of role number to point and role data
454456 role_data_map. insert (
@@ -496,7 +498,7 @@ fn update_role_data(
496498 }
497499 } ,
498500 } ;
499- let payment_key = get_payment_key_from_tx ( txn, role_data. payment_key ) ?;
501+ let payment_key = get_shelley_addr_from_tx ( txn, role_data. payment_key ) ?;
500502
501503 // Map of role number to point and role data
502504 // Note that new role data will overwrite the old one
@@ -517,10 +519,10 @@ fn update_role_data(
517519 Ok ( ( ) )
518520}
519521
520- /// Helper function for retrieving the payment key from the transaction.
521- fn get_payment_key_from_tx (
522+ /// Helper function for retrieving the Shelley address from the transaction.
523+ fn get_shelley_addr_from_tx (
522524 txn : & MultiEraTx , payment_key_ref : Option < i16 > ,
523- ) -> anyhow:: Result < Ed25519PublicKey > {
525+ ) -> anyhow:: Result < Cip19ShelleyAddrs > {
524526 // The index should exist since it pass the basic validation
525527 if let Some ( key_ref) = payment_key_ref {
526528 if let MultiEraTx :: Conway ( tx) = txn {
@@ -533,11 +535,11 @@ fn get_payment_key_from_tx(
533535 pallas:: ledger:: primitives:: conway:: PseudoTransactionOutput :: PostAlonzo (
534536 o,
535537 ) => {
536- let payment_key : Ed25519PublicKey =
538+ let shelley_addr : Cip19ShelleyAddrs =
537539 o. address . clone ( ) . try_into ( ) . map_err ( |_| {
538- anyhow:: anyhow!( "Failed to convert Vec<u8> to Ed25519PublicKey in payment key reference" )
540+ anyhow:: anyhow!( "Failed to convert Vec<u8> to Cip19ShelleyAddrs in payment key reference" )
539541 } ) ?;
540- return Ok ( payment_key ) ;
542+ return Ok ( shelley_addr ) ;
541543 } ,
542544 // Not support legacy form of transaction output
543545 pallas:: ledger:: primitives:: conway:: PseudoTransactionOutput :: Legacy ( _) => {
@@ -552,12 +554,12 @@ fn get_payment_key_from_tx(
552554 bail ! ( "Unsupported payment key reference to transaction input" ) ;
553555 }
554556 }
555- Ok ( Ed25519PublicKey :: default ( ) )
557+ Ok ( Cip19ShelleyAddrs :: default ( ) )
556558}
557559
558560/// Update the payment history given the tracking payment keys.
559561fn update_payment_history (
560- tracking_key : & Ed25519PublicKey , txn : & MultiEraTx , point_tx_idx : & PointTxIdx ,
562+ tracking_key : & Cip19ShelleyAddrs , txn : & MultiEraTx , point_tx_idx : & PointTxIdx ,
561563) -> anyhow:: Result < Vec < PaymentHistory > > {
562564 let mut payment_history = Vec :: new ( ) ;
563565 if let MultiEraTx :: Conway ( tx) = txn {
@@ -587,3 +589,98 @@ fn update_payment_history(
587589 }
588590 Ok ( payment_history)
589591}
592+
593+ #[ cfg( test) ]
594+ mod test {
595+ use minicbor:: { Decode , Decoder } ;
596+ use pallas:: { ledger:: traverse:: MultiEraTx , network:: miniprotocols:: Point } ;
597+
598+ use super :: RegistrationChain ;
599+ use crate :: cardano:: { cip509:: Cip509 , transaction:: raw_aux_data:: RawAuxData } ;
600+
601+ fn cip_509_aux_data ( tx : & MultiEraTx < ' _ > ) -> Vec < u8 > {
602+ let raw_auxiliary_data = tx
603+ . as_conway ( )
604+ . unwrap ( )
605+ . clone ( )
606+ . auxiliary_data
607+ . map ( |aux| aux. raw_cbor ( ) ) ;
608+
609+ let raw_cbor_data = match raw_auxiliary_data {
610+ pallas:: codec:: utils:: Nullable :: Some ( data) => Ok ( data) ,
611+ _ => Err ( "Auxiliary data not found" ) ,
612+ } ;
613+
614+ let auxiliary_data = RawAuxData :: new ( raw_cbor_data. expect ( "Failed to get raw cbor data" ) ) ;
615+ auxiliary_data
616+ . get_metadata ( 509 )
617+ . expect ( "Failed to get metadata" )
618+ . to_vec ( )
619+ }
620+
621+ fn conway_1 ( ) -> Vec < u8 > {
622+ hex:: decode ( include_str ! ( "../../test_data/cardano/conway_1.block" ) )
623+ . expect ( "Failed to decode hex block." )
624+ }
625+
626+ fn conway_4 ( ) -> Vec < u8 > {
627+ hex:: decode ( include_str ! ( "../../test_data/cardano/conway_4.block" ) )
628+ . expect ( "Failed to decode hex block." )
629+ }
630+
631+ #[ test]
632+ fn test_new_and_update_registration ( ) {
633+ let conway_block_data_1 = conway_1 ( ) ;
634+ let point_1 = Point :: new (
635+ 77_429_134 ,
636+ hex:: decode ( "62483f96613b4c48acd28de482eb735522ac180df61766bdb476a7bf83e7bb98" )
637+ . unwrap ( ) ,
638+ ) ;
639+ let multi_era_block_1 =
640+ pallas:: ledger:: traverse:: MultiEraBlock :: decode ( & conway_block_data_1)
641+ . expect ( "Failed to decode MultiEraBlock" ) ;
642+
643+ let transactions_1 = multi_era_block_1. txs ( ) ;
644+ // Forth transaction of this test data contains the CIP509 auxiliary data
645+ let tx_1 = transactions_1
646+ . get ( 3 )
647+ . expect ( "Failed to get transaction index" ) ;
648+
649+ let aux_data_1 = cip_509_aux_data ( tx_1) ;
650+ let mut decoder = Decoder :: new ( aux_data_1. as_slice ( ) ) ;
651+ let cip509_1 = Cip509 :: decode ( & mut decoder, & mut ( ) ) . expect ( "Failed to decode Cip509" ) ;
652+ let tracking_payment_keys = vec ! [ ] ;
653+
654+ let registration_chain =
655+ RegistrationChain :: new ( point_1. clone ( ) , tracking_payment_keys, 3 , tx_1, cip509_1) ;
656+ // Able to add chain root to the registration chain
657+ assert ! ( registration_chain. is_ok( ) ) ;
658+
659+ let conway_block_data_4 = conway_4 ( ) ;
660+ let point_4 = Point :: new (
661+ 77_436_369 ,
662+ hex:: decode ( "b174fc697126f05046b847d47e60d66cbedaf25240027f9c07f27150889aac24" )
663+ . unwrap ( ) ,
664+ ) ;
665+
666+ let multi_era_block_4 =
667+ pallas:: ledger:: traverse:: MultiEraBlock :: decode ( & conway_block_data_4)
668+ . expect ( "Failed to decode MultiEraBlock" ) ;
669+
670+ let transactions_4 = multi_era_block_4. txs ( ) ;
671+ // Second transaction of this test data contains the CIP509 auxiliary data
672+ let tx = transactions_4
673+ . get ( 1 )
674+ . expect ( "Failed to get transaction index" ) ;
675+
676+ let aux_data_4 = cip_509_aux_data ( tx) ;
677+ let mut decoder = Decoder :: new ( aux_data_4. as_slice ( ) ) ;
678+ let cip509 = Cip509 :: decode ( & mut decoder, & mut ( ) ) . expect ( "Failed to decode Cip509" ) ;
679+
680+ // Update the registration chain
681+ assert ! ( registration_chain
682+ . unwrap( )
683+ . update( point_4. clone( ) , 1 , tx, cip509)
684+ . is_ok( ) ) ;
685+ }
686+ }
0 commit comments