77from typing import Optional
88import unittest
99
10- try :
11- import payjoin .bitcoin as bitcoinffi
12- except ImportError :
13- bitcoinffi = None
14- raise unittest .SkipTest ("bitcoin_ffi helpers are not available in this binding" )
15-
1610# The below sys path setting is required to use the 'payjoin' module in the 'src' directory
1711# This script is in the 'tests' directory and the 'payjoin' module is in the 'src' directory
1812sys .path .insert (
@@ -101,15 +95,13 @@ async def process_receiver_proposal(
10195
10296 def create_receiver_context (
10397 self ,
104- receiver_address : bitcoinffi . Address ,
98+ address : str ,
10599 directory : str ,
106100 ohttp_keys : OhttpKeys ,
107101 recv_persister : InMemoryReceiverSessionEventLog ,
108102 ) -> Initialized :
109103 receiver = (
110- ReceiverBuilder (
111- address = receiver_address , directory = directory , ohttp_keys = ohttp_keys
112- )
104+ ReceiverBuilder (address = address , directory = directory , ohttp_keys = ohttp_keys )
113105 .build ()
114106 .save (recv_persister )
115107 )
@@ -207,10 +199,7 @@ async def process_provisional_proposal(
207199
208200 async def test_integration_v2_to_v2 (self ):
209201 try :
210- receiver_address = bitcoinffi .Address (
211- json .loads (self .receiver .call ("getnewaddress" , [])),
212- bitcoinffi .Network .REGTEST ,
213- )
202+ receiver_address = json .loads (self .receiver .call ("getnewaddress" , []))
214203 init_tracing ()
215204 services = TestServices .initialize ()
216205
@@ -282,32 +271,37 @@ async def test_integration_v2_to_v2(self):
282271 headers = {"Content-Type" : request .request .content_type },
283272 content = request .request .body ,
284273 )
285- checked_payjoin_proposal_psbt = (
286- send_ctx .process_response (response .content , request .ohttp_ctx )
287- .save (sender_persister )
288- .inner
289- )
290- print (f"checked_payjoin_proposal_psbt: { checked_payjoin_proposal_psbt } " )
291- self .assertIsNotNone (checked_payjoin_proposal_psbt )
274+ poll_outcome = send_ctx .process_response (
275+ response .content , request .ohttp_ctx
276+ ).save (sender_persister )
277+ print (f"poll_outcome: { poll_outcome } " )
278+ self .assertIsNotNone (poll_outcome )
279+ self .assertTrue (poll_outcome .is_PROGRESS ())
292280 payjoin_psbt = json .loads (
293281 self .sender .call (
294282 "walletprocesspsbt" ,
295- [checked_payjoin_proposal_psbt . serialize_base64 () ],
283+ [poll_outcome . psbt_base64 ],
296284 )
297285 )["psbt" ]
298286 final_psbt = json .loads (
299287 self .sender .call ("finalizepsbt" , [payjoin_psbt , json .dumps (False )])
300288 )["psbt" ]
301- payjoin_tx = bitcoinffi . Psbt . deserialize_base64 ( final_psbt ). extract_tx ()
302- self .sender .call (
303- "sendrawtransaction" , [ json . dumps ( payjoin_tx . serialize (). hex ()) ]
304- )
289+ final_tx_hex = json . loads (
290+ self .sender .call ("finalizepsbt" , [ final_psbt , json . dumps ( True )])
291+ )[ " hex" ]
292+ self . sender . call ( "sendrawtransaction" , [ json . dumps ( final_tx_hex )] )
305293
306294 # Check resulting transaction and balances
307- network_fees = bitcoinffi .Psbt .deserialize_base64 (final_psbt ).fee ().to_btc ()
295+ decoded_psbt = json .loads (
296+ self .sender .call ("decodepsbt" , [json .dumps (final_psbt )])
297+ )
298+ network_fees = float (decoded_psbt ["fee" ])
299+ decoded_tx = json .loads (
300+ self .sender .call ("decoderawtransaction" , [json .dumps (final_tx_hex )])
301+ )
308302 # Sender sent the entire value of their utxo to receiver (minus fees)
309- self .assertEqual (len (payjoin_tx . input () ), 2 )
310- self .assertEqual (len (payjoin_tx . output () ), 1 )
303+ self .assertEqual (len (decoded_tx [ "vin" ] ), 2 )
304+ self .assertEqual (len (decoded_tx [ "vout" ] ), 1 )
311305 self .assertEqual (
312306 float (
313307 json .loads (self .receiver .call ("getbalances" , []))["mine" ][
@@ -323,7 +317,7 @@ async def test_integration_v2_to_v2(self):
323317 raise
324318
325319
326- def build_sweep_psbt (sender : RpcClient , pj_uri : PjUri ) -> bitcoinffi . Psbt :
320+ def build_sweep_psbt (sender : RpcClient , pj_uri : PjUri ) -> str :
327321 outputs = {}
328322 outputs [pj_uri .address ()] = 50
329323 psbt = json .loads (
@@ -354,25 +348,21 @@ def build_sweep_psbt(sender: RpcClient, pj_uri: PjUri) -> bitcoinffi.Psbt:
354348def get_inputs (rpc_connection : RpcClient ) -> list [InputPair ]:
355349 utxos = json .loads (rpc_connection .call ("listunspent" , []))
356350 inputs = []
357- for utxo in utxos [:1 ]:
358- txin = bitcoinffi .TxIn (
359- previous_output = bitcoinffi .OutPoint (txid = utxo ["txid" ], vout = utxo ["vout" ]),
360- script_sig = bitcoinffi .Script (bytes ()),
351+ for utxo in utxos :
352+ txid = utxo ["txid" ]
353+ vout = utxo ["vout" ]
354+ script_pubkey = bytes .fromhex (utxo ["scriptPubKey" ])
355+ amount_sat = round (utxo ["amount" ] * 100_000_000 )
356+
357+ txin = PlainTxIn (
358+ previous_output = PlainOutPoint (txid = txid , vout = vout ),
359+ script_sig = bytes (),
361360 sequence = 0 ,
362361 witness = [],
363362 )
364- raw_tx = json .loads (
365- rpc_connection .call (
366- "gettransaction" ,
367- [json .dumps (utxo ["txid" ]), json .dumps (True ), json .dumps (True )],
368- )
369- )
370- prev_out = raw_tx ["decoded" ]["vout" ][utxo ["vout" ]]
371- prev_spk = bitcoinffi .Script (bytes .fromhex (prev_out ["scriptPubKey" ]["hex" ]))
372- prev_amount = bitcoinffi .Amount .from_btc (prev_out ["value" ])
373- tx_out = bitcoinffi .TxOut (value = prev_amount , script_pubkey = prev_spk )
374- psbt_in = PsbtInput (
375- witness_utxo = tx_out , redeem_script = None , witness_script = None
363+ witness_utxo = PlainTxOut (value_sat = amount_sat , script_pubkey = script_pubkey )
364+ psbt_in = PlainPsbtInput (
365+ witness_utxo = witness_utxo , redeem_script = None , witness_script = None
376366 )
377367 inputs .append (InputPair (txin = txin , psbtin = psbt_in , expected_weight = None ))
378368
@@ -402,15 +392,41 @@ def __init__(self, connection: RpcClient):
402392
403393 def callback (self , script ):
404394 try :
405- address = bitcoinffi .Address .from_script (
406- bitcoinffi .Script (script ), bitcoinffi .Network .REGTEST
395+ script_hex = bytes (script ).hex ()
396+ decoded_script = json .loads (
397+ self .connection .call ("decodescript" , [json .dumps (script_hex )])
407398 )
408- return json .loads (self .connection .call ("getaddressinfo" , [str (address )]))[
409- "ismine"
410- ]
399+
400+ candidates = []
401+ if isinstance (decoded_script .get ("address" ), str ):
402+ candidates .append (decoded_script ["address" ])
403+ if isinstance (decoded_script .get ("addresses" ), list ):
404+ candidates .extend (
405+ addr
406+ for addr in decoded_script ["addresses" ]
407+ if isinstance (addr , str )
408+ )
409+ if isinstance (decoded_script .get ("p2sh" ), str ):
410+ candidates .append (decoded_script ["p2sh" ])
411+ segwit = decoded_script .get ("segwit" )
412+ if isinstance (segwit , dict ):
413+ if isinstance (segwit .get ("address" ), str ):
414+ candidates .append (segwit ["address" ])
415+ if isinstance (segwit .get ("addresses" ), list ):
416+ candidates .extend (
417+ addr for addr in segwit ["addresses" ] if isinstance (addr , str )
418+ )
419+
420+ for addr in candidates :
421+ info = json .loads (
422+ self .connection .call ("getaddressinfo" , [json .dumps (addr )])
423+ )
424+ if info .get ("ismine" ) is True :
425+ return True
426+ return False
411427 except Exception as e :
412428 print (f"An error occurred: { e } " )
413- return None
429+ return False
414430
415431
416432class CheckInputsNotSeenCallback (IsOutputKnown ):
0 commit comments