@@ -310,10 +310,7 @@ impl WantsOutputs {
310310 && txo. value < original_output. value
311311 {
312312 return Err (
313- InternalOutputSubstitutionError :: OutputSubstitutionDisabled (
314- "Decreasing the receiver output value is not allowed" ,
315- )
316- . into ( ) ,
313+ InternalOutputSubstitutionError :: DecreasedValueWhenDisabled . into ( ) ,
317314 ) ;
318315 }
319316 outputs. push ( txo) ;
@@ -322,10 +319,8 @@ impl WantsOutputs {
322319 None => {
323320 if self . params . disable_output_substitution {
324321 return Err (
325- InternalOutputSubstitutionError :: OutputSubstitutionDisabled (
326- "Changing the receiver output script pubkey is not allowed" ,
327- )
328- . into ( ) ,
322+ InternalOutputSubstitutionError :: ScriptPubKeyChangedWhenDisabled
323+ . into ( ) ,
329324 ) ;
330325 }
331326 let index = rng. gen_range ( 0 ..replacement_outputs. len ( ) ) ;
@@ -788,20 +783,36 @@ pub(crate) mod test {
788783 use std:: str:: FromStr ;
789784
790785 use bitcoin:: { Address , Network } ;
791- use payjoin_test_utils:: ORIGINAL_PSBT ;
786+ use payjoin_test_utils:: { BoxError , ORIGINAL_PSBT , QUERY_PARAMS } ;
792787 use rand:: rngs:: StdRng ;
793788 use rand:: SeedableRng ;
794789
795790 use super :: * ;
796- pub const QUERY_PARAMS : & str = "maxadditionalfeecontribution=182&additionalfeeoutputindex=0" ;
797-
798- pub ( crate ) fn proposal_from_test_vector (
799- ) -> Result < UncheckedProposal , Box < dyn std:: error:: Error > > {
791+ pub ( crate ) fn proposal_from_test_vector ( ) -> Result < UncheckedProposal , BoxError > {
800792 let pairs = url:: form_urlencoded:: parse ( QUERY_PARAMS . as_bytes ( ) ) ;
801793 let params = Params :: from_query_pairs ( pairs, & [ 1 ] ) ?;
802794 Ok ( UncheckedProposal { psbt : bitcoin:: Psbt :: from_str ( ORIGINAL_PSBT ) ?, params } )
803795 }
804796
797+ fn wants_outputs_from_test_vector (
798+ proposal : UncheckedProposal ,
799+ ) -> Result < WantsOutputs , BoxError > {
800+ Ok ( proposal
801+ . assume_interactive_receiver ( )
802+ . check_inputs_not_owned ( |_| Ok ( false ) )
803+ . expect ( "No inputs should be owned" )
804+ . check_no_inputs_seen_before ( |_| Ok ( false ) )
805+ . expect ( "No inputs should be seen before" )
806+ . identify_receiver_outputs ( |script| {
807+ let network = Network :: Bitcoin ;
808+ Ok ( Address :: from_script ( script, network) . unwrap ( )
809+ == Address :: from_str ( "3CZZi7aWFugaCdUCS15dgrUUViupmB8bVM" )
810+ . unwrap ( )
811+ . require_network ( network)
812+ . unwrap ( ) )
813+ } ) ?)
814+ }
815+
805816 #[ test]
806817 fn can_get_proposal_from_request ( ) {
807818 let proposal = proposal_from_test_vector ( ) ;
@@ -935,6 +946,75 @@ pub(crate) mod test {
935946 ) ;
936947 }
937948
949+ #[ test]
950+ fn test_pjos_disabled ( ) {
951+ let mut proposal = proposal_from_test_vector ( ) . unwrap ( ) ;
952+ // Specify outputsubstitution is disabled
953+ proposal. params . disable_output_substitution = true ;
954+ let wants_outputs = wants_outputs_from_test_vector ( proposal) . unwrap ( ) ;
955+
956+ let output_value =
957+ wants_outputs. original_psbt . unsigned_tx . output [ wants_outputs. change_vout ] . value
958+ + Amount :: ONE_SAT ;
959+ let outputs = vec ! [ TxOut {
960+ value: output_value,
961+ script_pubkey: wants_outputs. original_psbt. unsigned_tx. output
962+ [ wants_outputs. change_vout]
963+ . script_pubkey
964+ . clone( ) ,
965+ } ] ;
966+ let increased_amount = wants_outputs. clone ( ) . replace_receiver_outputs (
967+ outputs,
968+ wants_outputs. original_psbt . unsigned_tx . output [ wants_outputs. change_vout ]
969+ . script_pubkey
970+ . as_script ( ) ,
971+ ) ;
972+ assert ! ( increased_amount. is_ok( ) , "Replacement Outputs should be a valid WantsOutput" ) ;
973+ assert_ne ! ( wants_outputs. payjoin_psbt, increased_amount. unwrap( ) . payjoin_psbt) ;
974+
975+ let output_value =
976+ wants_outputs. original_psbt . unsigned_tx . output [ wants_outputs. change_vout ] . value
977+ - Amount :: ONE_SAT ;
978+ let outputs = vec ! [ TxOut {
979+ value: output_value,
980+ script_pubkey: wants_outputs. original_psbt. unsigned_tx. output
981+ [ wants_outputs. change_vout]
982+ . script_pubkey
983+ . clone( ) ,
984+ } ] ;
985+ let decreased_amount = wants_outputs. clone ( ) . replace_receiver_outputs (
986+ outputs,
987+ wants_outputs. original_psbt . unsigned_tx . output [ wants_outputs. change_vout ]
988+ . script_pubkey
989+ . as_script ( ) ,
990+ ) ;
991+ match decreased_amount {
992+ Ok ( _) => panic ! ( "Expected error, got success" ) ,
993+ Err ( error) => {
994+ assert_eq ! (
995+ error,
996+ OutputSubstitutionError :: from(
997+ InternalOutputSubstitutionError :: DecreasedValueWhenDisabled
998+ )
999+ ) ;
1000+ }
1001+ } ;
1002+
1003+ let script = Script :: new ( ) ;
1004+ let replace_receiver_script_pubkey = wants_outputs. substitute_receiver_script ( script) ;
1005+ match replace_receiver_script_pubkey {
1006+ Ok ( _) => panic ! ( "Expected error, got success" ) ,
1007+ Err ( error) => {
1008+ assert_eq ! (
1009+ error,
1010+ OutputSubstitutionError :: from(
1011+ InternalOutputSubstitutionError :: ScriptPubKeyChangedWhenDisabled
1012+ )
1013+ ) ;
1014+ }
1015+ } ;
1016+ }
1017+
9381018 #[ test]
9391019 fn test_interleave_shuffle ( ) {
9401020 let mut original1 = vec ! [ 1 , 2 , 3 ] ;
0 commit comments