@@ -568,7 +568,7 @@ impl Receiver<MaybeInputsOwned> {
568568 /// An attacker can try to spend the receiver's own inputs. This check prevents that.
569569 pub fn check_inputs_not_owned (
570570 self ,
571- is_owned : impl Fn ( & Script ) -> Result < bool , ImplementationError > ,
571+ is_owned : & mut impl FnMut ( & Script ) -> Result < bool , ImplementationError > ,
572572 ) -> MaybeFatalTransition < SessionEvent , Receiver < MaybeInputsSeen > , ReplyableError > {
573573 let inner = match self . state . v1 . clone ( ) . check_inputs_not_owned ( is_owned) {
574574 Ok ( inner) => inner,
@@ -618,7 +618,7 @@ impl Receiver<MaybeInputsSeen> {
618618 /// original proposal PSBT of the current, new payjoin.
619619 pub fn check_no_inputs_seen_before (
620620 self ,
621- is_known : impl Fn ( & OutPoint ) -> Result < bool , ImplementationError > ,
621+ is_known : & mut impl FnMut ( & OutPoint ) -> Result < bool , ImplementationError > ,
622622 ) -> MaybeFatalTransition < SessionEvent , Receiver < OutputsUnknown > , ReplyableError > {
623623 let inner = match self . state . v1 . clone ( ) . check_no_inputs_seen_before ( is_known) {
624624 Ok ( inner) => inner,
@@ -673,7 +673,7 @@ impl Receiver<OutputsUnknown> {
673673 /// outputs.
674674 pub fn identify_receiver_outputs (
675675 self ,
676- is_receiver_output : impl Fn ( & Script ) -> Result < bool , ImplementationError > ,
676+ is_receiver_output : & mut impl FnMut ( & Script ) -> Result < bool , ImplementationError > ,
677677 ) -> MaybeFatalTransition < SessionEvent , Receiver < WantsOutputs > , ReplyableError > {
678678 let inner = match self . state . inner . clone ( ) . identify_receiver_outputs ( is_receiver_output) {
679679 Ok ( inner) => inner,
@@ -1099,6 +1099,50 @@ pub mod test {
10991099 }
11001100 }
11011101
1102+ pub ( crate ) fn maybe_inputs_owned_v2_from_test_vector ( ) -> MaybeInputsOwned {
1103+ let pairs = url:: form_urlencoded:: parse ( QUERY_PARAMS . as_bytes ( ) ) ;
1104+ let params = Params :: from_query_pairs ( pairs, & [ Version :: Two ] )
1105+ . expect ( "Test utils query params should not fail" ) ;
1106+ MaybeInputsOwned {
1107+ v1 : v1:: MaybeInputsOwned { psbt : PARSED_ORIGINAL_PSBT . clone ( ) , params } ,
1108+ context : SHARED_CONTEXT . clone ( ) ,
1109+ }
1110+ }
1111+
1112+ #[ test]
1113+ fn test_v2_mutable_receiver_state_closures ( ) {
1114+ let mut call_count = 0 ;
1115+ let maybe_inputs_owned = maybe_inputs_owned_v2_from_test_vector ( ) ;
1116+ let receiver = v2:: Receiver { state : maybe_inputs_owned } ;
1117+
1118+ fn mock_callback ( call_count : & mut usize , ret : bool ) -> Result < bool , ImplementationError > {
1119+ * call_count += 1 ;
1120+ Ok ( ret)
1121+ }
1122+
1123+ let maybe_inputs_seen =
1124+ receiver. check_inputs_not_owned ( & mut |_| mock_callback ( & mut call_count, false ) ) ;
1125+ assert_eq ! ( call_count, 1 ) ;
1126+
1127+ let outputs_unknown = maybe_inputs_seen
1128+ . 0
1129+ . map_err ( |_| "Check inputs owned closure failed" . to_string ( ) )
1130+ . expect ( "Next receiver state should be accessible" )
1131+ . 1
1132+ . check_no_inputs_seen_before ( & mut |_| mock_callback ( & mut call_count, false ) ) ;
1133+ assert_eq ! ( call_count, 2 ) ;
1134+
1135+ let _wants_outputs = outputs_unknown
1136+ . 0
1137+ . map_err ( |_| "Check no inputs seen closure failed" . to_string ( ) )
1138+ . expect ( "Next receiver state should be accessible" )
1139+ . 1
1140+ . identify_receiver_outputs ( & mut |_| mock_callback ( & mut call_count, true ) ) ;
1141+ // there are 2 receiver outputs so we should expect this callback to run twice incrementing
1142+ // call count twice
1143+ assert_eq ! ( call_count, 4 ) ;
1144+ }
1145+
11021146 #[ test]
11031147 fn test_unchecked_proposal_transient_error ( ) -> Result < ( ) , BoxError > {
11041148 let unchecked_proposal = unchecked_proposal_v2_from_test_vector ( ) ;
@@ -1127,7 +1171,7 @@ pub mod test {
11271171 let receiver = v2:: Receiver { state : unchecked_proposal } ;
11281172
11291173 let maybe_inputs_owned = receiver. assume_interactive_receiver ( ) ;
1130- let maybe_inputs_seen = maybe_inputs_owned. 0 . 1 . check_inputs_not_owned ( |_| {
1174+ let maybe_inputs_seen = maybe_inputs_owned. 0 . 1 . check_inputs_not_owned ( & mut |_| {
11311175 Err ( ImplementationError :: new ( ReplyableError :: Implementation ( "mock error" . into ( ) ) ) )
11321176 } ) ;
11331177
@@ -1150,9 +1194,9 @@ pub mod test {
11501194 let receiver = v2:: Receiver { state : unchecked_proposal } ;
11511195
11521196 let maybe_inputs_owned = receiver. assume_interactive_receiver ( ) ;
1153- let maybe_inputs_seen = maybe_inputs_owned. 0 . 1 . check_inputs_not_owned ( |_| Ok ( false ) ) ;
1197+ let maybe_inputs_seen = maybe_inputs_owned. 0 . 1 . check_inputs_not_owned ( & mut |_| Ok ( false ) ) ;
11541198 let outputs_unknown = match maybe_inputs_seen. 0 {
1155- Ok ( state) => state. 1 . check_no_inputs_seen_before ( |_| {
1199+ Ok ( state) => state. 1 . check_no_inputs_seen_before ( & mut |_| {
11561200 Err ( ImplementationError :: new ( ReplyableError :: Implementation ( "mock error" . into ( ) ) ) )
11571201 } ) ,
11581202 Err ( _) => panic ! ( "Expected Ok, got Err" ) ,
@@ -1177,13 +1221,13 @@ pub mod test {
11771221 let receiver = v2:: Receiver { state : unchecked_proposal } ;
11781222
11791223 let maybe_inputs_owned = receiver. assume_interactive_receiver ( ) ;
1180- let maybe_inputs_seen = maybe_inputs_owned. 0 . 1 . check_inputs_not_owned ( |_| Ok ( false ) ) ;
1224+ let maybe_inputs_seen = maybe_inputs_owned. 0 . 1 . check_inputs_not_owned ( & mut |_| Ok ( false ) ) ;
11811225 let outputs_unknown = match maybe_inputs_seen. 0 {
1182- Ok ( state) => state. 1 . check_no_inputs_seen_before ( |_| Ok ( false ) ) ,
1226+ Ok ( state) => state. 1 . check_no_inputs_seen_before ( & mut |_| Ok ( false ) ) ,
11831227 Err ( _) => panic ! ( "Expected Ok, got Err" ) ,
11841228 } ;
11851229 let wants_outputs = match outputs_unknown. 0 {
1186- Ok ( state) => state. 1 . identify_receiver_outputs ( |_| {
1230+ Ok ( state) => state. 1 . identify_receiver_outputs ( & mut |_| {
11871231 Err ( ImplementationError :: new ( ReplyableError :: Implementation ( "mock error" . into ( ) ) ) )
11881232 } ) ,
11891233 Err ( _) => panic ! ( "Expected Ok, got Err" ) ,
0 commit comments