@@ -9,16 +9,18 @@ use crate::xdr_verify::{
99use rstest:: rstest;
1010use sha2:: { Digest , Sha256 } ;
1111use std:: collections:: BTreeMap ;
12- use stellar_xdr:: curr:: {
13- AccountId , CreateAccountOp , GeneralizedTransactionSet , Hash , LedgerHeader , LedgerHeaderExt ,
12+ use stellar_xdr:: {
13+ AccountId , ContractId , CreateAccountOp , GeneralizedTransactionSet , Hash , HostFunction ,
14+ InvokeContractArgs , InvokeHostFunctionOp , LedgerHeader , LedgerHeaderExt ,
1415 LedgerHeaderHistoryEntry , LedgerHeaderHistoryEntryExt , LedgerScpMessages , Limits , Memo ,
15- MuxedAccount , Operation , OperationBody , Preconditions , PublicKey , ScpHistoryEntry ,
16- ScpHistoryEntryV0 , SequenceNumber , TimePoint , Transaction , TransactionEnvelope ,
17- TransactionHistoryEntry , TransactionHistoryEntryExt , TransactionHistoryResultEntry ,
18- TransactionHistoryResultEntryExt , TransactionPhase , TransactionResult , TransactionResultExt ,
19- TransactionResultPair , TransactionResultResult , TransactionResultSet , TransactionSet ,
20- TransactionSetV1 , TransactionV0 , TransactionV0Envelope , TransactionV0Ext ,
21- TransactionV1Envelope , Uint256 , VecM , WriteXdr ,
16+ MuxedAccount , Operation , OperationBody , Preconditions , PublicKey , ScAddress , ScSymbol , ScVal ,
17+ ScpHistoryEntry , ScpHistoryEntryV0 , SequenceNumber , SorobanAddressCredentials ,
18+ SorobanAuthorizationEntry , SorobanAuthorizedFunction , SorobanAuthorizedInvocation ,
19+ SorobanCredentials , TimePoint , Transaction , TransactionEnvelope , TransactionHistoryEntry ,
20+ TransactionHistoryEntryExt , TransactionHistoryResultEntry , TransactionHistoryResultEntryExt ,
21+ TransactionPhase , TransactionResult , TransactionResultExt , TransactionResultPair ,
22+ TransactionResultResult , TransactionResultSet , TransactionSet , TransactionSetV1 , TransactionV0 ,
23+ TransactionV0Envelope , TransactionV0Ext , TransactionV1Envelope , Uint256 , VecM , WriteXdr ,
2224} ;
2325
2426fn frame_xdr < T : WriteXdr > ( entry : & T ) -> Vec < u8 > {
@@ -76,7 +78,49 @@ fn tx_v1_envelope(id: u8) -> TransactionEnvelope {
7678 cond : Preconditions :: None ,
7779 memo : Memo :: None ,
7880 operations : vec ! [ create_account_operation( id) ] . try_into ( ) . unwrap ( ) ,
79- ext : stellar_xdr:: curr:: TransactionExt :: V0 ,
81+ ext : stellar_xdr:: TransactionExt :: V0 ,
82+ } ,
83+ signatures : VecM :: default ( ) ,
84+ } )
85+ }
86+
87+ /// Soroban transaction whose auth entry uses the CAP-0071 (protocol 27)
88+ /// `SOROBAN_CREDENTIALS_ADDRESS_V2` arm, which pre-27 XDR cannot decode.
89+ fn tx_soroban_envelope_with_address_v2_auth ( id : u8 ) -> TransactionEnvelope {
90+ let invoke_args = InvokeContractArgs {
91+ contract_address : ScAddress :: Contract ( ContractId ( Hash ( [ id; 32 ] ) ) ) ,
92+ function_name : ScSymbol ( "transfer" . try_into ( ) . unwrap ( ) ) ,
93+ args : VecM :: default ( ) ,
94+ } ;
95+ let auth = SorobanAuthorizationEntry {
96+ credentials : SorobanCredentials :: AddressV2 ( SorobanAddressCredentials {
97+ address : ScAddress :: Account ( account_id ( id) ) ,
98+ nonce : 1 ,
99+ signature_expiration_ledger : 100 ,
100+ signature : ScVal :: Void ,
101+ } ) ,
102+ root_invocation : SorobanAuthorizedInvocation {
103+ function : SorobanAuthorizedFunction :: ContractFn ( invoke_args. clone ( ) ) ,
104+ sub_invocations : VecM :: default ( ) ,
105+ } ,
106+ } ;
107+ TransactionEnvelope :: Tx ( TransactionV1Envelope {
108+ tx : Transaction {
109+ source_account : muxed_account ( id) ,
110+ fee : 100 ,
111+ seq_num : SequenceNumber ( i64:: from ( id) + 1 ) ,
112+ cond : Preconditions :: None ,
113+ memo : Memo :: None ,
114+ operations : vec ! [ Operation {
115+ source_account: None ,
116+ body: OperationBody :: InvokeHostFunction ( InvokeHostFunctionOp {
117+ host_function: HostFunction :: InvokeContract ( invoke_args) ,
118+ auth: vec![ auth] . try_into( ) . unwrap( ) ,
119+ } ) ,
120+ } ]
121+ . try_into ( )
122+ . unwrap ( ) ,
123+ ext : stellar_xdr:: TransactionExt :: V0 ,
80124 } ,
81125 signatures : VecM :: default ( ) ,
82126 } )
@@ -106,8 +150,8 @@ fn v1_history_entry(
106150 prev_hash : [ u8 ; 32 ] ,
107151 txs : Vec < TransactionEnvelope > ,
108152) -> TransactionHistoryEntry {
109- let component = stellar_xdr:: curr :: TxSetComponent :: TxsetCompTxsMaybeDiscountedFee (
110- stellar_xdr:: curr :: TxSetComponentTxsMaybeDiscountedFee {
153+ let component = stellar_xdr:: TxSetComponent :: TxsetCompTxsMaybeDiscountedFee (
154+ stellar_xdr:: TxSetComponentTxsMaybeDiscountedFee {
111155 base_fee : None ,
112156 txs : txs. try_into ( ) . unwrap ( ) ,
113157 } ,
@@ -166,11 +210,11 @@ fn create_minimal_ledger_header(
166210 LedgerHeader {
167211 ledger_version : 21 ,
168212 previous_ledger_hash : Hash ( prev_hash) ,
169- scp_value : stellar_xdr:: curr :: StellarValue {
213+ scp_value : stellar_xdr:: StellarValue {
170214 tx_set_hash : Hash ( tx_set_hash) ,
171215 close_time : TimePoint ( 0 ) ,
172216 upgrades : VecM :: default ( ) ,
173- ext : stellar_xdr:: curr :: StellarValueExt :: Basic ,
217+ ext : stellar_xdr:: StellarValueExt :: Basic ,
174218 } ,
175219 tx_set_result_hash : Hash ( result_hash) ,
176220 bucket_list_hash : Hash ( [ 0 ; 32 ] ) ,
@@ -408,6 +452,22 @@ fn test_parse_transaction_entries_v1_non_empty() {
408452 assert ! ( !is_empty_tx_set_hash( & parsed[ & 100 ] , & Hash ( prev_hash) ) ) ;
409453}
410454
455+ #[ test]
456+ fn test_parse_transaction_entries_v1_with_cap71_address_v2_credentials ( ) {
457+ let prev_hash = [ 0x24 ; 32 ] ;
458+ let entry = v1_history_entry (
459+ 100 ,
460+ prev_hash,
461+ vec ! [ tx_soroban_envelope_with_address_v2_auth( 1 ) ] ,
462+ ) ;
463+ let parsed = parse_transaction_entries ( & frame_xdr ( & entry) ) . unwrap ( ) ;
464+
465+ let TransactionHistoryEntryExt :: V1 ( generalized) = & entry. ext else {
466+ panic ! ( "expected V1 entry" ) ;
467+ } ;
468+ assert_eq ! ( parsed[ & 100 ] , compute_v1_tx_set_hash( generalized) . unwrap( ) ) ;
469+ }
470+
411471#[ test]
412472fn test_compute_v0_tx_set_hash_matches_manual_hash ( ) {
413473 let prev_hash = [ 0x10 ; 32 ] ;
@@ -450,14 +510,12 @@ fn test_compute_v1_tx_set_hash_matches_manual_hash() {
450510 let generalized = GeneralizedTransactionSet :: V1 ( TransactionSetV1 {
451511 previous_ledger_hash : Hash ( [ 0x11 ; 32 ] ) ,
452512 phases : vec ! [ TransactionPhase :: V0 (
453- vec![
454- stellar_xdr:: curr:: TxSetComponent :: TxsetCompTxsMaybeDiscountedFee (
455- stellar_xdr:: curr:: TxSetComponentTxsMaybeDiscountedFee {
456- base_fee: None ,
457- txs: vec![ tx_v1_envelope( 1 ) ] . try_into( ) . unwrap( ) ,
458- } ,
459- ) ,
460- ]
513+ vec![ stellar_xdr:: TxSetComponent :: TxsetCompTxsMaybeDiscountedFee (
514+ stellar_xdr:: TxSetComponentTxsMaybeDiscountedFee {
515+ base_fee: None ,
516+ txs: vec![ tx_v1_envelope( 1 ) ] . try_into( ) . unwrap( ) ,
517+ } ,
518+ ) ]
461519 . try_into( )
462520 . unwrap( ) ,
463521 ) ]
0 commit comments