From 703ae04dcc6fc66afc662a94aecadb1decc756e2 Mon Sep 17 00:00:00 2001 From: undeath Date: Sat, 14 Jul 2018 21:37:55 +0200 Subject: [PATCH] remove wallet.sign() --- jmclient/jmclient/maker.py | 36 ++++++++++++---------- jmclient/jmclient/taker.py | 53 ++++++++++++-------------------- jmclient/jmclient/taker_utils.py | 27 ++++++++++------ jmclient/test/test_maker.py | 11 +++---- jmclient/test/test_taker.py | 27 ++++++---------- 5 files changed, 70 insertions(+), 84 deletions(-) diff --git a/jmclient/jmclient/maker.py b/jmclient/jmclient/maker.py index 500a50b..9690d12 100644 --- a/jmclient/jmclient/maker.py +++ b/jmclient/jmclient/maker.py @@ -3,16 +3,13 @@ from __future__ import print_function import base64 import pprint -import random import sys -import time -import copy +from binascii import unhexlify import btc from jmclient.configure import jm_single, get_p2pk_vbyte, get_p2sh_vbyte from jmbase.support import get_log from jmclient.support import (calc_cj_fee) -from jmclient.wallet import estimate_tx_fee from jmclient.podle import (generate_podle, get_podle_commitments, verify_podle, PoDLE, PoDLEError, generate_podle_error_string) from twisted.internet import task @@ -75,7 +72,11 @@ class Maker(object): if res[0]['value'] < reqd_amt: reason = "commitment utxo too small: " + str(res[0]['value']) return reject(reason) - if res[0]['address'] != self.wallet.pubkey_to_address(cr_dict['P']): + + # FIXME: This only works if taker's commitment address is of same type + # as our wallet. + if res[0]['address'] != \ + self.wallet.pubkey_to_addr(unhexlify(cr_dict['P'])): reason = "Invalid podle pubkey: " + str(cr_dict['P']) return reject(reason) @@ -114,22 +115,25 @@ class Maker(object): jlog.info('goodtx') sigs = [] utxos = offerinfo["utxos"] + + our_inputs = {} for index, ins in enumerate(tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) - if utxo not in utxos.keys(): + if utxo not in utxos: continue - addr = utxos[utxo]['address'] - amount = utxos[utxo]["value"] - txs = self.wallet.sign(txhex, index, - self.wallet.get_key_from_addr(addr), - amount=amount) - sigmsg = btc.deserialize(txs)["ins"][index]["script"].decode("hex") - if "txinwitness" in btc.deserialize(txs)["ins"][index].keys(): + script = self.wallet.addr_to_script(utxos[utxo]['address']) + amount = utxos[utxo]['value'] + our_inputs[index] = (script, amount) + + txs = self.wallet.sign_tx(btc.deserialize(unhexlify(txhex)), our_inputs) + + for index in our_inputs: + sigmsg = txs['ins'][index]['script'] + if 'txinwitness' in txs['ins'][index]: #We prepend the witness data since we want (sig, pub, scriptCode); #also, the items in witness are not serialize_script-ed. - sigmsg = "".join([btc.serialize_script_unit( - x.decode("hex")) for x in btc.deserialize( - txs)["ins"][index]["txinwitness"]]) + sigmsg + sigmsg = b''.join(btc.serialize_script_unit(x) + for x in txs['ins'][index]['txinwitness']) + sigmsg sigs.append(base64.b64encode(sigmsg)) return (True, sigs) diff --git a/jmclient/jmclient/taker.py b/jmclient/jmclient/taker.py index bcc02a4..dd75722 100644 --- a/jmclient/jmclient/taker.py +++ b/jmclient/jmclient/taker.py @@ -4,6 +4,7 @@ from __future__ import print_function import base64 import pprint import random +from binascii import hexlify, unhexlify import btc from jmclient.configure import jm_single, get_p2pk_vbyte, get_p2sh_vbyte @@ -25,7 +26,6 @@ class Taker(object): wallet, schedule, order_chooser=weighted_order_choose, - sign_method=None, callbacks=None, tdestaddrs=None, ignored_makers=None): @@ -98,9 +98,6 @@ class Taker(object): self.schedule_index = -1 self.utxos = {} self.tdestaddrs = [] if not tdestaddrs else tdestaddrs - #allow custom wallet-based clients to use their own signing code; - #currently only setting "wallet" is allowed, calls wallet.sign_tx(tx) - self.sign_method = sign_method self.filter_orders_callback = callbacks[0] self.taker_info_callback = callbacks[1] if not self.taker_info_callback: @@ -367,7 +364,9 @@ class Taker(object): #Construct the Bitcoin address for the auth_pub field #Ensure that at least one address from utxos corresponds. input_addresses = [d['address'] for d in utxo_data] - auth_address = self.wallet.pubkey_to_address(auth_pub) + # FIXME: This only works if taker's commitment address is of same type + # as our wallet. + auth_address = self.wallet.pubkey_to_addr(unhexlify(auth_pub)) if not auth_address in input_addresses: jlog.warn("ERROR maker's (" + nick + ")" " authorising pubkey is not included " @@ -710,37 +709,23 @@ class Taker(object): #Note: donation code removed (possibly temporarily) raise NotImplementedError - def sign_tx(self, tx, i, priv, amount): - if self.my_cj_addr: - return self.wallet.sign(tx, i, priv, amount) - else: - #Note: donation code removed (possibly temporarily) - raise NotImplementedError - def self_sign(self): # now sign it ourselves - tx = btc.serialize(self.latest_tx) - if self.sign_method == "wallet": - #Currently passes addresses of to-be-signed inputs - #to backend wallet; this is correct for Electrum, may need - #different info for other backends. - addrs = {} - for index, ins in enumerate(self.latest_tx['ins']): - utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) - if utxo not in self.input_utxos.keys(): - continue - addrs[index] = self.input_utxos[utxo]['address'] - tx = self.wallet.sign_tx(tx, addrs) - else: - for index, ins in enumerate(self.latest_tx['ins']): - utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) - if utxo not in self.input_utxos.keys(): - continue - addr = self.input_utxos[utxo]['address'] - amount = self.input_utxos[utxo]["value"] - tx = self.sign_tx(tx, index, self.wallet.get_key_from_addr(addr), - amount) - self.latest_tx = btc.deserialize(tx) + our_inputs = {} + for index, ins in enumerate(self.latest_tx['ins']): + utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) + if utxo not in self.input_utxos.keys(): + continue + script = self.wallet.addr_to_script(self.input_utxos[utxo]['address']) + amount = self.input_utxos[utxo]['value'] + our_inputs[index] = (script, amount) + + # FIXME: ugly hack + tx_bin = btc.deserialize(unhexlify(btc.serialize(self.latest_tx))) + self.wallet.sign_tx(tx_bin, our_inputs) + + self.latest_tx = btc.deserialize(hexlify(btc.serialize(tx_bin))) + def push(self): tx = btc.serialize(self.latest_tx) diff --git a/jmclient/jmclient/taker_utils.py b/jmclient/jmclient/taker_utils.py index 32e8a8d..25eb295 100644 --- a/jmclient/jmclient/taker_utils.py +++ b/jmclient/jmclient/taker_utils.py @@ -5,10 +5,11 @@ import pprint import os import time import numbers +from binascii import hexlify, unhexlify from .configure import get_log, jm_single, validate_address from .schedule import human_readable_schedule_entry, tweak_tumble_schedule from .wallet import BaseWallet, estimate_tx_fee -from jmclient import mktx, deserialize, sign, txhash +from .btc import mktx, serialize, deserialize, sign, txhash log = get_log() """ @@ -74,14 +75,7 @@ def direct_send(wallet, amount, mixdepth, destaddr, answeryes=False, log.info("Using a fee of : " + str(fee_est) + " satoshis.") if amount != 0: log.info("Using a change value of: " + str(changeval) + " satoshis.") - tx = mktx(utxos.keys(), outs) - stx = deserialize(tx) - for index, ins in enumerate(stx['ins']): - utxo = ins['outpoint']['hash'] + ':' + str( - ins['outpoint']['index']) - addr = utxos[utxo]['address'] - amount = utxos[utxo]['value'] - tx = sign(tx, index, wallet.get_key_from_addr(addr), amount=amount) + tx = sign_tx(wallet, mktx(utxos.keys(), outs), utxos) txsigned = deserialize(tx) log.info("Got signed transaction:\n") log.info(tx + "\n") @@ -106,6 +100,21 @@ def direct_send(wallet, amount, mixdepth, destaddr, answeryes=False, return txid +def sign_tx(wallet, tx, utxos): + stx = deserialize(tx) + our_inputs = {} + for index, ins in enumerate(stx['ins']): + utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) + script = wallet.addr_to_script(utxos[utxo]['address']) + amount = utxos[utxo]['value'] + our_inputs[index] = (script, amount) + + # FIXME: ugly hack + tx_bin = deserialize(unhexlify(serialize(stx))) + wallet.sign_tx(tx_bin, our_inputs) + return hexlify(serialize(tx_bin)) + + def import_new_addresses(wallet, addr_list): # FIXME: same code as in maker.py and taker.py bci = jm_single().bc_interface diff --git a/jmclient/test/test_maker.py b/jmclient/test/test_maker.py index 6cdfbf7..4a1c823 100644 --- a/jmclient/test/test_maker.py +++ b/jmclient/test/test_maker.py @@ -2,10 +2,11 @@ from __future__ import print_function -from jmclient import AbstractWallet, Maker, btc, get_p2sh_vbyte, get_p2pk_vbyte, \ +from jmclient import Maker, btc, get_p2sh_vbyte, get_p2pk_vbyte, \ load_program_config, jm_single import jmclient from commontest import DummyBlockchainInterface +from test_taker import DummyWallet import struct import binascii @@ -13,10 +14,6 @@ from itertools import chain import pytest -class MockWallet(AbstractWallet): - pass - - class OfflineMaker(Maker): def try_to_create_my_orders(self): self.sync_wait_loop.stop() @@ -116,7 +113,7 @@ def test_verify_unsigned_tx_sw_valid(setup_env_nodeps): p2sh_gen = address_p2sh_generator() p2pkh_gen = address_p2pkh_generator() - wallet = MockWallet() + wallet = DummyWallet() maker = OfflineMaker(wallet) cj_addr, cj_script = next(p2sh_gen) @@ -149,7 +146,7 @@ def test_verify_unsigned_tx_nonsw_valid(setup_env_nodeps): p2sh_gen = address_p2sh_generator() p2pkh_gen = address_p2pkh_generator() - wallet = MockWallet() + wallet = DummyWallet() maker = OfflineMaker(wallet) cj_addr, cj_script = next(p2pkh_gen) diff --git a/jmclient/test/test_taker.py b/jmclient/test/test_taker.py index 4d9310a..585358b 100644 --- a/jmclient/test/test_taker.py +++ b/jmclient/test/test_taker.py @@ -11,12 +11,12 @@ import json from base64 import b64encode from jmclient import ( load_program_config, jm_single, set_commitment_file, get_commitment_file, - LegacyWallet, Taker, VolatileStorage, get_p2sh_vbyte, get_network) + SegwitLegacyWallet, Taker, VolatileStorage, get_p2sh_vbyte, get_network) from taker_test_data import (t_utxos_by_mixdepth, t_selected_utxos, t_orderbook, t_maker_response, t_chosen_orders, t_dummy_ext) -class DummyWallet(LegacyWallet): +class DummyWallet(SegwitLegacyWallet): def __init__(self): storage = VolatileStorage() super(DummyWallet, self).initialize(storage, get_network(), @@ -79,10 +79,6 @@ class DummyWallet(LegacyWallet): """ return 'p2sh-p2wpkh' - @classmethod - def pubkey_to_address(cls, pubkey): - return SegwitWallet.pubkey_to_address(pubkey) - def get_key_from_addr(self, addr): """usable addresses: privkey all 1s, 2s, 3s, ... :""" privs = [x*32 + "\x01" for x in [chr(y) for y in range(1,6)]] @@ -111,7 +107,7 @@ def dummy_filter_orderbook(orders_fees, cjamount): print("calling dummy filter orderbook") return True -def get_taker(schedule=None, schedule_len=0, sign_method=None, on_finished=None, +def get_taker(schedule=None, schedule_len=0, on_finished=None, filter_orders=None): if not schedule: #note, for taker.initalize() this will result in junk @@ -120,8 +116,7 @@ def get_taker(schedule=None, schedule_len=0, sign_method=None, on_finished=None, on_finished_callback = on_finished if on_finished else taker_finished filter_orders_callback = filter_orders if filter_orders else dummy_filter_orderbook return Taker(DummyWallet(), schedule, - callbacks=[filter_orders_callback, None, on_finished_callback], - sign_method=sign_method) + callbacks=[filter_orders_callback, None, on_finished_callback]) def test_filter_rejection(createcmtdata): def filter_orders_reject(orders_feesl, cjamount): @@ -340,8 +335,6 @@ def test_taker_init(createcmtdata, schedule, highfee, toomuchcoins, minmakers, taker.my_cj_addr = None with pytest.raises(NotImplementedError) as e_info: taker.prepare_my_bitcoin_data() - with pytest.raises(NotImplementedError) as e_info: - taker.sign_tx("a", "b", "c", "d") with pytest.raises(NotImplementedError) as e_info: a = taker.coinjoin_address() taker.wallet.inject_addr_get_failure = True @@ -377,14 +370,12 @@ def test_unconfirm_confirm(schedule_len): assert not test_unconfirm_confirm.txflag @pytest.mark.parametrize( - "dummyaddr, signmethod, schedule", + "dummyaddr, schedule", [ - ("mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ", None, - [(0, 20000000, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw", 0)]), - ("mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ", "wallet", - [(0, 20000000, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw", 0)]), + ("mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ", + [(0, 20000000, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw", 0)]) ]) -def test_on_sig(createcmtdata, dummyaddr, signmethod, schedule): +def test_on_sig(createcmtdata, dummyaddr, schedule): #plan: create a new transaction with known inputs and dummy outputs; #then, create a signature with various inputs, pass in in b64 to on_sig. #in order for it to verify, the DummyBlockchainInterface will have to @@ -410,7 +401,7 @@ def test_on_sig(createcmtdata, dummyaddr, signmethod, schedule): de_tx = bitcoin.deserialize(tx) #prepare the Taker with the right intermediate data - taker = get_taker(schedule=schedule, sign_method=signmethod) + taker = get_taker(schedule=schedule) taker.nonrespondants=["cp1", "cp2", "cp3"] taker.latest_tx = de_tx #my inputs are the first 2 utxos