Browse Source

remove wallet.sign()

master
undeath 8 years ago
parent
commit
703ae04dcc
  1. 36
      jmclient/jmclient/maker.py
  2. 53
      jmclient/jmclient/taker.py
  3. 27
      jmclient/jmclient/taker_utils.py
  4. 11
      jmclient/test/test_maker.py
  5. 27
      jmclient/test/test_taker.py

36
jmclient/jmclient/maker.py

@ -3,16 +3,13 @@ from __future__ import print_function
import base64 import base64
import pprint import pprint
import random
import sys import sys
import time from binascii import unhexlify
import copy
import btc import btc
from jmclient.configure import jm_single, get_p2pk_vbyte, get_p2sh_vbyte from jmclient.configure import jm_single, get_p2pk_vbyte, get_p2sh_vbyte
from jmbase.support import get_log from jmbase.support import get_log
from jmclient.support import (calc_cj_fee) 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, from jmclient.podle import (generate_podle, get_podle_commitments, verify_podle,
PoDLE, PoDLEError, generate_podle_error_string) PoDLE, PoDLEError, generate_podle_error_string)
from twisted.internet import task from twisted.internet import task
@ -75,7 +72,11 @@ class Maker(object):
if res[0]['value'] < reqd_amt: if res[0]['value'] < reqd_amt:
reason = "commitment utxo too small: " + str(res[0]['value']) reason = "commitment utxo too small: " + str(res[0]['value'])
return reject(reason) 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']) reason = "Invalid podle pubkey: " + str(cr_dict['P'])
return reject(reason) return reject(reason)
@ -114,22 +115,25 @@ class Maker(object):
jlog.info('goodtx') jlog.info('goodtx')
sigs = [] sigs = []
utxos = offerinfo["utxos"] utxos = offerinfo["utxos"]
our_inputs = {}
for index, ins in enumerate(tx['ins']): for index, ins in enumerate(tx['ins']):
utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
if utxo not in utxos.keys(): if utxo not in utxos:
continue continue
addr = utxos[utxo]['address'] script = self.wallet.addr_to_script(utxos[utxo]['address'])
amount = utxos[utxo]["value"] amount = utxos[utxo]['value']
txs = self.wallet.sign(txhex, index, our_inputs[index] = (script, amount)
self.wallet.get_key_from_addr(addr),
amount=amount) txs = self.wallet.sign_tx(btc.deserialize(unhexlify(txhex)), our_inputs)
sigmsg = btc.deserialize(txs)["ins"][index]["script"].decode("hex")
if "txinwitness" in btc.deserialize(txs)["ins"][index].keys(): 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); #We prepend the witness data since we want (sig, pub, scriptCode);
#also, the items in witness are not serialize_script-ed. #also, the items in witness are not serialize_script-ed.
sigmsg = "".join([btc.serialize_script_unit( sigmsg = b''.join(btc.serialize_script_unit(x)
x.decode("hex")) for x in btc.deserialize( for x in txs['ins'][index]['txinwitness']) + sigmsg
txs)["ins"][index]["txinwitness"]]) + sigmsg
sigs.append(base64.b64encode(sigmsg)) sigs.append(base64.b64encode(sigmsg))
return (True, sigs) return (True, sigs)

53
jmclient/jmclient/taker.py

@ -4,6 +4,7 @@ from __future__ import print_function
import base64 import base64
import pprint import pprint
import random import random
from binascii import hexlify, unhexlify
import btc import btc
from jmclient.configure import jm_single, get_p2pk_vbyte, get_p2sh_vbyte from jmclient.configure import jm_single, get_p2pk_vbyte, get_p2sh_vbyte
@ -25,7 +26,6 @@ class Taker(object):
wallet, wallet,
schedule, schedule,
order_chooser=weighted_order_choose, order_chooser=weighted_order_choose,
sign_method=None,
callbacks=None, callbacks=None,
tdestaddrs=None, tdestaddrs=None,
ignored_makers=None): ignored_makers=None):
@ -98,9 +98,6 @@ class Taker(object):
self.schedule_index = -1 self.schedule_index = -1
self.utxos = {} self.utxos = {}
self.tdestaddrs = [] if not tdestaddrs else tdestaddrs 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.filter_orders_callback = callbacks[0]
self.taker_info_callback = callbacks[1] self.taker_info_callback = callbacks[1]
if not self.taker_info_callback: if not self.taker_info_callback:
@ -367,7 +364,9 @@ class Taker(object):
#Construct the Bitcoin address for the auth_pub field #Construct the Bitcoin address for the auth_pub field
#Ensure that at least one address from utxos corresponds. #Ensure that at least one address from utxos corresponds.
input_addresses = [d['address'] for d in utxo_data] 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: if not auth_address in input_addresses:
jlog.warn("ERROR maker's (" + nick + ")" jlog.warn("ERROR maker's (" + nick + ")"
" authorising pubkey is not included " " authorising pubkey is not included "
@ -710,37 +709,23 @@ class Taker(object):
#Note: donation code removed (possibly temporarily) #Note: donation code removed (possibly temporarily)
raise NotImplementedError 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): def self_sign(self):
# now sign it ourselves # now sign it ourselves
tx = btc.serialize(self.latest_tx) our_inputs = {}
if self.sign_method == "wallet": for index, ins in enumerate(self.latest_tx['ins']):
#Currently passes addresses of to-be-signed inputs utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
#to backend wallet; this is correct for Electrum, may need if utxo not in self.input_utxos.keys():
#different info for other backends. continue
addrs = {} script = self.wallet.addr_to_script(self.input_utxos[utxo]['address'])
for index, ins in enumerate(self.latest_tx['ins']): amount = self.input_utxos[utxo]['value']
utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) our_inputs[index] = (script, amount)
if utxo not in self.input_utxos.keys():
continue # FIXME: ugly hack
addrs[index] = self.input_utxos[utxo]['address'] tx_bin = btc.deserialize(unhexlify(btc.serialize(self.latest_tx)))
tx = self.wallet.sign_tx(tx, addrs) self.wallet.sign_tx(tx_bin, our_inputs)
else:
for index, ins in enumerate(self.latest_tx['ins']): self.latest_tx = btc.deserialize(hexlify(btc.serialize(tx_bin)))
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)
def push(self): def push(self):
tx = btc.serialize(self.latest_tx) tx = btc.serialize(self.latest_tx)

27
jmclient/jmclient/taker_utils.py

@ -5,10 +5,11 @@ import pprint
import os import os
import time import time
import numbers import numbers
from binascii import hexlify, unhexlify
from .configure import get_log, jm_single, validate_address from .configure import get_log, jm_single, validate_address
from .schedule import human_readable_schedule_entry, tweak_tumble_schedule from .schedule import human_readable_schedule_entry, tweak_tumble_schedule
from .wallet import BaseWallet, estimate_tx_fee 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() 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.") log.info("Using a fee of : " + str(fee_est) + " satoshis.")
if amount != 0: if amount != 0:
log.info("Using a change value of: " + str(changeval) + " satoshis.") log.info("Using a change value of: " + str(changeval) + " satoshis.")
tx = mktx(utxos.keys(), outs) tx = sign_tx(wallet, mktx(utxos.keys(), outs), utxos)
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)
txsigned = deserialize(tx) txsigned = deserialize(tx)
log.info("Got signed transaction:\n") log.info("Got signed transaction:\n")
log.info(tx + "\n") log.info(tx + "\n")
@ -106,6 +100,21 @@ def direct_send(wallet, amount, mixdepth, destaddr, answeryes=False,
return txid 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): def import_new_addresses(wallet, addr_list):
# FIXME: same code as in maker.py and taker.py # FIXME: same code as in maker.py and taker.py
bci = jm_single().bc_interface bci = jm_single().bc_interface

11
jmclient/test/test_maker.py

@ -2,10 +2,11 @@
from __future__ import print_function 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 load_program_config, jm_single
import jmclient import jmclient
from commontest import DummyBlockchainInterface from commontest import DummyBlockchainInterface
from test_taker import DummyWallet
import struct import struct
import binascii import binascii
@ -13,10 +14,6 @@ from itertools import chain
import pytest import pytest
class MockWallet(AbstractWallet):
pass
class OfflineMaker(Maker): class OfflineMaker(Maker):
def try_to_create_my_orders(self): def try_to_create_my_orders(self):
self.sync_wait_loop.stop() self.sync_wait_loop.stop()
@ -116,7 +113,7 @@ def test_verify_unsigned_tx_sw_valid(setup_env_nodeps):
p2sh_gen = address_p2sh_generator() p2sh_gen = address_p2sh_generator()
p2pkh_gen = address_p2pkh_generator() p2pkh_gen = address_p2pkh_generator()
wallet = MockWallet() wallet = DummyWallet()
maker = OfflineMaker(wallet) maker = OfflineMaker(wallet)
cj_addr, cj_script = next(p2sh_gen) 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() p2sh_gen = address_p2sh_generator()
p2pkh_gen = address_p2pkh_generator() p2pkh_gen = address_p2pkh_generator()
wallet = MockWallet() wallet = DummyWallet()
maker = OfflineMaker(wallet) maker = OfflineMaker(wallet)
cj_addr, cj_script = next(p2pkh_gen) cj_addr, cj_script = next(p2pkh_gen)

27
jmclient/test/test_taker.py

@ -11,12 +11,12 @@ import json
from base64 import b64encode from base64 import b64encode
from jmclient import ( from jmclient import (
load_program_config, jm_single, set_commitment_file, get_commitment_file, 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, from taker_test_data import (t_utxos_by_mixdepth, t_selected_utxos, t_orderbook,
t_maker_response, t_chosen_orders, t_dummy_ext) t_maker_response, t_chosen_orders, t_dummy_ext)
class DummyWallet(LegacyWallet): class DummyWallet(SegwitLegacyWallet):
def __init__(self): def __init__(self):
storage = VolatileStorage() storage = VolatileStorage()
super(DummyWallet, self).initialize(storage, get_network(), super(DummyWallet, self).initialize(storage, get_network(),
@ -79,10 +79,6 @@ class DummyWallet(LegacyWallet):
""" """
return 'p2sh-p2wpkh' return 'p2sh-p2wpkh'
@classmethod
def pubkey_to_address(cls, pubkey):
return SegwitWallet.pubkey_to_address(pubkey)
def get_key_from_addr(self, addr): def get_key_from_addr(self, addr):
"""usable addresses: privkey all 1s, 2s, 3s, ... :""" """usable addresses: privkey all 1s, 2s, 3s, ... :"""
privs = [x*32 + "\x01" for x in [chr(y) for y in range(1,6)]] 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") print("calling dummy filter orderbook")
return True 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): filter_orders=None):
if not schedule: if not schedule:
#note, for taker.initalize() this will result in junk #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 on_finished_callback = on_finished if on_finished else taker_finished
filter_orders_callback = filter_orders if filter_orders else dummy_filter_orderbook filter_orders_callback = filter_orders if filter_orders else dummy_filter_orderbook
return Taker(DummyWallet(), schedule, return Taker(DummyWallet(), schedule,
callbacks=[filter_orders_callback, None, on_finished_callback], callbacks=[filter_orders_callback, None, on_finished_callback])
sign_method=sign_method)
def test_filter_rejection(createcmtdata): def test_filter_rejection(createcmtdata):
def filter_orders_reject(orders_feesl, cjamount): 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 taker.my_cj_addr = None
with pytest.raises(NotImplementedError) as e_info: with pytest.raises(NotImplementedError) as e_info:
taker.prepare_my_bitcoin_data() 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: with pytest.raises(NotImplementedError) as e_info:
a = taker.coinjoin_address() a = taker.coinjoin_address()
taker.wallet.inject_addr_get_failure = True taker.wallet.inject_addr_get_failure = True
@ -377,14 +370,12 @@ def test_unconfirm_confirm(schedule_len):
assert not test_unconfirm_confirm.txflag assert not test_unconfirm_confirm.txflag
@pytest.mark.parametrize( @pytest.mark.parametrize(
"dummyaddr, signmethod, schedule", "dummyaddr, schedule",
[ [
("mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ", None, ("mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ",
[(0, 20000000, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw", 0)]), [(0, 20000000, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw", 0)])
("mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ", "wallet",
[(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; #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. #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 #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) de_tx = bitcoin.deserialize(tx)
#prepare the Taker with the right intermediate data #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.nonrespondants=["cp1", "cp2", "cp3"]
taker.latest_tx = de_tx taker.latest_tx = de_tx
#my inputs are the first 2 utxos #my inputs are the first 2 utxos

Loading…
Cancel
Save