Skip to content

Commit

Permalink
Support output of PSBT instead of broadcast in direct_send
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamISZ committed Apr 23, 2020
1 parent 48267ac commit 381423b
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 33 deletions.
8 changes: 8 additions & 0 deletions jmclient/jmclient/cli_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,14 @@ def get_sendpayment_parser():
help='specify recipient IRC nick for a '
'p2ep style payment, for example:\n'
'J5Ehn3EieVZFtm4q ')
parser.add_option('--psbt',
action='store_true',
dest='with_psbt',
default=False,
help='output as psbt instead of '
'broadcasting the transaction. '
'Currently only works with direct '
'send (-N 0).')

add_common_options(parser)
return parser
86 changes: 54 additions & 32 deletions jmclient/jmclient/taker_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from .schedule import human_readable_schedule_entry, tweak_tumble_schedule,\
schedule_to_text
from .wallet import BaseWallet, estimate_tx_fee, compute_tx_locktime
from jmbitcoin import make_shuffled_tx, amount_to_str
from jmbitcoin import (make_shuffled_tx, amount_to_str,
PartiallySignedTransaction, CMutableTxOut)
from jmbase.support import EXIT_SUCCESS
log = get_log()

Expand All @@ -21,7 +22,7 @@

def direct_send(wallet_service, amount, mixdepth, destaddr, answeryes=False,
accept_callback=None, info_callback=None,
return_transaction=False):
return_transaction=False, with_final_psbt=False):
"""Send coins directly from one mixdepth to one destination address;
does not need IRC. Sweep as for normal sendpayment (set amount=0).
If answeryes is True, callback/command line query is not performed.
Expand All @@ -38,8 +39,13 @@ def direct_send(wallet_service, amount, mixdepth, destaddr, answeryes=False,
pushed), and returns nothing.
This function returns:
The txid if transaction is pushed, False otherwise,
or the full CMutableTransaction if return_transaction is True.
1. False if there is any failure.
2. The txid if transaction is pushed, and return_transaction is False,
and with_final_psbt is False.
3. The full CMutableTransaction is return_transaction is True and
with_final_psbt is False.
4. The PSBT object if with_final_psbt is True, and in
this case the transaction is *NOT* broadcast.
"""
#Sanity checks
assert validate_address(destaddr)[0]
Expand Down Expand Up @@ -81,37 +87,53 @@ def direct_send(wallet_service, amount, mixdepth, destaddr, answeryes=False,
tx = make_shuffled_tx(list(utxos.keys()), outs, 2, compute_tx_locktime())

inscripts = {}
spent_outs = []
for i, txinp in enumerate(tx.vin):
u = (txinp.prevout.hash[::-1], txinp.prevout.n)
inscripts[i] = (utxos[u]["script"], utxos[u]["value"])
success, msg = wallet_service.sign_tx(tx, inscripts)
if not success:
log.error("Failed to sign transaction, quitting. Error msg: " + msg)
return
log.info("Got signed transaction:\n")
log.info(pformat(str(tx)))
log.info("In serialized form (for copy-paste):")
log.info(bintohex(tx.serialize()))
actual_amount = amount if amount != 0 else total_inputs_val - fee_est
log.info("Sends: " + amount_to_str(actual_amount) + " to address: " + destaddr)
if not answeryes:
if not accept_callback:
if input('Would you like to push to the network? (y/n):')[0] != 'y':
log.info("You chose not to broadcast the transaction, quitting.")
return False
else:
accepted = accept_callback(pformat(str(tx)), destaddr, actual_amount,
fee_est)
if not accepted:
return False
jm_single().bc_interface.pushtx(tx.serialize())
txid = bintohex(tx.GetTxid()[::-1])
successmsg = "Transaction sent: " + txid
cb = log.info if not info_callback else info_callback
cb(successmsg)
txinfo = txid if not return_transaction else tx
return txinfo

spent_outs.append(CMutableTxOut(utxos[u]["value"],
utxos[u]["script"]))
if with_final_psbt:
# here we have the PSBTWalletMixin do the signing stage
# for us:
new_psbt = wallet_service.create_psbt_from_tx(tx, spent_outs=spent_outs)
serialized_psbt, err = wallet_service.sign_psbt(new_psbt.serialize())
if err:
log.error("Failed to sign PSBT, quitting. Error message: " + err)
return False
new_psbt_signed = PartiallySignedTransaction.deserialize(serialized_psbt)
print("Completed PSBT created: ")
print(pformat(new_psbt_signed))
# TODO add more readable info here as for case below.
return new_psbt_signed
else:
success, msg = wallet_service.sign_tx(tx, inscripts)
if not success:
log.error("Failed to sign transaction, quitting. Error msg: " + msg)
return
log.info("Got signed transaction:\n")
log.info(pformat(str(tx)))
log.info("In serialized form (for copy-paste):")
log.info(bintohex(tx.serialize()))
actual_amount = amount if amount != 0 else total_inputs_val - fee_est
log.info("Sends: " + amount_to_str(actual_amount) + " to address: " + destaddr)
if not answeryes:
if not accept_callback:
if input('Would you like to push to the network? (y/n):')[0] != 'y':
log.info("You chose not to broadcast the transaction, quitting.")
return False
else:
accepted = accept_callback(pformat(str(tx)), destaddr, actual_amount,
fee_est)
if not accepted:
return False
jm_single().bc_interface.pushtx(tx.serialize())
txid = bintohex(tx.GetTxid()[::-1])
successmsg = "Transaction sent: " + txid
cb = log.info if not info_callback else info_callback
cb(successmsg)
txinfo = txid if not return_transaction else tx
return txinfo

def sign_tx(wallet_service, tx, utxos):
stx = deserialize(tx)
Expand Down
7 changes: 6 additions & 1 deletion scripts/sendpayment.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,12 @@ def main():
.format(exp_tx_fees_ratio))

if options.makercount == 0 and not options.p2ep:
direct_send(wallet_service, amount, mixdepth, destaddr, options.answeryes)
tx = direct_send(wallet_service, amount, mixdepth, destaddr,
options.answeryes, with_final_psbt=options.with_psbt)
if options.with_psbt:
log.info("This PSBT is fully signed and can be sent externally for "
"broadcasting:")
log.info(tx.to_base64())
return

if wallet.get_txtype() == 'p2pkh':
Expand Down

0 comments on commit 381423b

Please sign in to comment.