Browse Source

Add support for taker using a non-segwit wallet

As for maker, to use this feature set segwit = false
in the POLICY section of the config file.
This commit does *not* include support in the GUI.
Additionally, minor fixes to utility scripts for non-sw wallets,
and updated add-utxo tool to support non-sw wallets.
Bugfixes to wallet_utils to support non-sw wallets
and signmessage.
master
AdamISZ 8 years ago
parent
commit
619b4a123f
No known key found for this signature in database
GPG Key ID: B3AE09F1E9A3197A
  1. 4
      jmclient/jmclient/taker.py
  2. 12
      jmclient/jmclient/wallet_utils.py
  3. 9
      jmclient/test/test_taker.py
  4. 2
      jmclient/test/test_wallets.py
  5. 11
      scripts/add-utxo.py
  6. 14
      scripts/jmtainter.py
  7. 9
      scripts/joinmarket-qt.py
  8. 17
      scripts/sendpayment.py
  9. 3
      scripts/sendtomany.py
  10. 4
      scripts/tumbler.py
  11. 10
      test/common.py

4
jmclient/jmclient/taker.py

@ -303,8 +303,7 @@ 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 = btc.pubkey_to_p2sh_p2wpkh_address(auth_pub,
get_p2sh_vbyte())
auth_address = self.wallet.pubkey_to_address(auth_pub)
if not auth_address in input_addresses:
jlog.warn("ERROR maker's (" + nick + ")"
" authorising pubkey is not included "
@ -479,7 +478,6 @@ class Taker(object):
else:
jlog.debug("Invalid signature message - more than 3 items")
break
print("Got sig_deserialized: ", sig_deserialized)
ver_amt = utxo_data[i]['value'] if wit else None
sig_good = btc.verify_tx_input(txhex, u[0], utxo_data[i]['script'],
ver_sig, ver_pub, witness=wit,

12
jmclient/jmclient/wallet_utils.py

@ -800,8 +800,9 @@ def wallet_importprivkey(wallet, mixdepth):
def wallet_dumpprivkey(wallet, hdpath):
pathlist = bip32pathparse(hdpath)
print('got pathlist: ' + str(pathlist))
if pathlist and len(pathlist) == 5:
cointype, purpose, m, forchange, k = pathlist
if pathlist and len(pathlist) in [5, 4]:
#note here we assume the path conforms to Wallet or SegwitWallet(BIP49) standard
m, forchange, k = pathlist[-3:]
key = wallet.get_key(m, forchange, k)
wifkey = btc.wif_compressed_privkey(key, vbyte=get_p2pk_vbyte())
return wifkey
@ -810,9 +811,10 @@ def wallet_dumpprivkey(wallet, hdpath):
def wallet_signmessage(wallet, hdpath, message):
if hdpath.startswith(wallet.get_root_path()):
m, forchange, k = [int(y) for y in hdpath[4:].split('/')]
hp = bip32pathparse(hdpath)
m, forchange, k = hp[-3:]
key = wallet.get_key(m, forchange, k)
addr = btc.privkey_to_address(key, magicbyte=get_p2sh_vbyte())
addr = wallet.pubkey_to_address(btc.privkey_to_pubkey(key))
print('Using address: ' + addr)
else:
print('%s is not a valid hd wallet path' % hdpath)
@ -908,7 +910,7 @@ def wallet_tool_main(wallet_root_path):
wallet_importprivkey(wallet, options.mixdepth)
return "Key import completed."
elif method == "signmessage":
return wallet_signmessage(wallet, options.hd_path, args[1])
return wallet_signmessage(wallet, options.hd_path, args[2])
#Testing (can port to test modules, TODO)
if __name__ == "__main__":

9
jmclient/test/test_taker.py

@ -10,8 +10,8 @@ import pytest
import json
from base64 import b64encode
from jmclient import (load_program_config, jm_single, set_commitment_file,
get_commitment_file, AbstractWallet, Taker,
get_p2sh_vbyte)
get_commitment_file, AbstractWallet, Taker, SegwitWallet,
get_p2sh_vbyte, get_p2pk_vbyte)
from taker_test_data import (t_utxos_by_mixdepth, t_selected_utxos, t_orderbook,
t_maker_response, t_chosen_orders, t_dummy_ext)
@ -52,8 +52,9 @@ class DummyWallet(AbstractWallet):
"""
return 'p2sh-p2wpkh'
def get_vbyte(self):
return get_p2sh_vbyte()
@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, ... :"""

2
jmclient/test/test_wallets.py

@ -14,7 +14,7 @@ from mnemonic import Mnemonic
from ConfigParser import SafeConfigParser, NoSectionError
from decimal import Decimal
from commontest import (interact, make_wallets,
make_sign_and_push, DummyBlockchainInterface)
make_sign_and_push)
import json
import jmbitcoin as bitcoin

11
scripts/add-utxo.py

@ -15,7 +15,7 @@ from pprint import pformat
from optparse import OptionParser
import jmclient.btc as btc
from jmbase import get_password
from jmclient import (load_program_config, jm_single, get_p2pk_vbyte, SegwitWallet,
from jmclient import (load_program_config, jm_single, get_p2pk_vbyte, get_wallet_cls,
WalletError, sync_wallet, add_external_commitments,
generate_podle, update_commitments, PoDLE,
set_commitment_file, get_podle_commitments,
@ -73,7 +73,7 @@ def main():
"BE CAREFUL about handling private keys! "
"Don't do this in insecure environments. "
"Also note this ONLY works for standard (p2pkh) utxos."
"Also note this ONLY works for standard (p2pkh or p2sh-p2wpkh) utxos."
)
parser.add_option(
'-r',
@ -91,7 +91,7 @@ def main():
type='str',
dest='in_json',
help='name of json formatted file containing utxos with private keys, as '
'output from "python wallet-tool.py -u -p walletname showutxos"'
'output from "python wallet-tool.py -p walletname showutxos"'
)
parser.add_option(
'-w',
@ -177,7 +177,7 @@ def main():
while True:
pwd = get_password("Enter wallet decryption passphrase: ")
try:
wallet = SegwitWallet(options.loadwallet,
wallet = get_wallet_cls()(options.loadwallet,
pwd,
options.maxmixdepth,
options.gaplimit)
@ -231,7 +231,8 @@ def main():
else:
quit(parser, 'Invalid syntax')
if options.validate or options.vonly:
if not validate_utxo_data(utxo_data, segwit=True):
sw = False if jm_single().config.get("POLICY", "segwit") == "false" else True
if not validate_utxo_data(utxo_data, segwit=sw):
quit(parser, "Utxos did not validate, quitting")
if options.vonly:
sys.exit(0)

14
scripts/jmtainter.py

@ -17,8 +17,8 @@ from pprint import pformat
import jmbitcoin as btc
from jmclient import (load_program_config, validate_address, jm_single,
WalletError, sync_wallet, RegtestBitcoinCoreInterface,
estimate_tx_fee, Wallet, SegwitWallet, get_p2pk_vbyte,
get_p2sh_vbyte)
estimate_tx_fee, SegwitWallet, get_p2pk_vbyte,
get_p2sh_vbyte, get_wallet_cls)
from jmbase.support import get_password
def get_parser():
@ -79,15 +79,13 @@ def is_utxo(utxo):
return True
def cli_get_wallet(wallet_name, sync=True):
walletclass = SegwitWallet if jm_single().config.get(
"POLICY", "segwit") == "true" else Wallet
if not os.path.exists(os.path.join('wallets', wallet_name)):
wallet = walletclass(wallet_name, None, max_mix_depth=options.amtmixdepths)
wallet = get_wallet_cls()(wallet_name, None, max_mix_depth=options.amtmixdepths)
else:
while True:
try:
pwd = get_password("Enter wallet decryption passphrase: ")
wallet = walletclass(wallet_name, pwd, max_mix_depth=options.amtmixdepths)
wallet = get_wallet_cls()(wallet_name, pwd, max_mix_depth=options.amtmixdepths)
except WalletError:
print("Wrong password, try again.")
continue
@ -213,6 +211,10 @@ if __name__ == "__main__":
parser = get_parser()
(options, args) = parser.parse_args()
load_program_config()
if get_wallet_cls() != SegwitWallet:
print("Only segwit wallets are supported; remove any setting of `segwit`"
" in `POLICY` in joinmarket.cfg. Quitting.")
exit(0)
#default args causes wallet sync here:
wallet = cli_get_wallet(args[0])
if args[1] not in ['make', 'take']:

9
scripts/joinmarket-qt.py

@ -1577,6 +1577,15 @@ except Exception as e:
])
JMQtMessageBox(None, config_load_error, mbtype='crit', title='failed to load')
exit(1)
#refuse to load non-segwit wallet (needs extra work in wallet-utils).
if not jm_single().config.get("POLICY", "segwit") == "true":
wallet_load_error = ''.join(["Joinmarket-Qt only supports segwit based wallets, ",
"please edit the config file and remove any setting ",
"of the field `segwit` in the `POLICY` section."])
JMQtMessageBox(None, wallet_load_error, mbtype='crit',
title='Incompatible wallet type')
exit(1)
update_config_for_gui()
#to allow testing of confirm/unconfirm callback for multiple txs

17
scripts/sendpayment.py

@ -22,9 +22,9 @@ from jmclient import (Taker, load_program_config, get_schedule,
validate_address, jm_single, WalletError,
choose_orders, choose_sweep_orders,
cheapest_order_choose, weighted_order_choose,
Wallet, BitcoinCoreWallet, sync_wallet,
RegtestBitcoinCoreInterface, estimate_tx_fee,
direct_send, SegwitWallet)
sync_wallet, RegtestBitcoinCoreInterface,
estimate_tx_fee, direct_send, get_wallet_cls,
BitcoinCoreWallet)
from twisted.python.log import startLogging
from jmbase.support import get_log, debug_dump_object, get_password
from cli_options import get_sendpayment_parser
@ -57,8 +57,6 @@ def main():
parser = get_sendpayment_parser()
(options, args) = parser.parse_args()
load_program_config()
walletclass = SegwitWallet if jm_single().config.get(
"POLICY", "segwit") == "true" else Wallet
if options.schedule == '' and len(args) < 3:
parser.error('Needs a wallet, amount and destination address')
sys.exit(0)
@ -129,12 +127,12 @@ def main():
#to ensure we have enough, must be at least (requested index+1)
max_mix_depth = max([mixdepth+1, options.amtmixdepths])
if not os.path.exists(os.path.join('wallets', wallet_name)):
wallet = walletclass(wallet_name, None, max_mix_depth, options.gaplimit)
wallet = get_wallet_cls()(wallet_name, None, max_mix_depth, options.gaplimit)
else:
while True:
try:
pwd = get_password("Enter wallet decryption passphrase: ")
wallet = walletclass(wallet_name, pwd, max_mix_depth, options.gaplimit)
wallet = get_wallet_cls()(wallet_name, pwd, max_mix_depth, options.gaplimit)
except WalletError:
print("Wrong password, try again.")
continue
@ -155,11 +153,6 @@ def main():
direct_send(wallet, amount, mixdepth, destaddr, options.answeryes)
return
if walletclass == Wallet:
print("Only direct sends (use -N 0) are supported for "
"legacy (non-segwit) wallets.")
return
def filter_orders_callback(orders_fees, cjamount):
orders, total_cj_fee = orders_fees
log.info("Chose these orders: " +pprint.pformat(orders))

3
scripts/sendtomany.py

@ -103,6 +103,9 @@ def main():
if not validate_address(d):
quit(parser, "Address was not valid; wrong network?: " + d)
txsigned = sign(u, priv, destaddrs, segwit = not options.nonsegwit)
if not txsigned:
log.info("Transaction signing operation failed, see debug messages for details.")
return
log.debug("Got signed transaction:\n" + txsigned)
log.debug("Deserialized:")
log.debug(pformat(btc.deserialize(txsigned)))

4
scripts/tumbler.py

@ -15,7 +15,7 @@ from twisted.python.log import startLogging
from jmclient import (Taker, load_program_config, get_schedule,
weighted_order_choose, JMClientProtocolFactory,
start_reactor, validate_address, jm_single, WalletError,
Wallet, SegwitWallet, sync_wallet, get_tumble_schedule,
get_wallet_cls, sync_wallet, get_tumble_schedule,
RegtestBitcoinCoreInterface, estimate_tx_fee,
tweak_tumble_schedule, human_readable_schedule_entry,
schedule_to_text, restart_waiter, get_tumble_log,
@ -40,7 +40,7 @@ def main():
wallet_name = args[0]
max_mix_depth = options['mixdepthsrc'] + options['mixdepthcount']
if not os.path.exists(os.path.join('wallets', wallet_name)):
wallet = SegwitWallet(wallet_name, None, max_mix_depth)
wallet = get_wallet_cls()(wallet_name, None, max_mix_depth)
else:
while True:
try:

10
test/common.py

@ -12,7 +12,7 @@ from decimal import Decimal
data_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.insert(0, os.path.join(data_dir))
from jmclient import SegwitWallet, Wallet, get_log, estimate_tx_fee, jm_single
from jmclient import get_wallet_cls, get_log, estimate_tx_fee, jm_single
import jmbitcoin as btc
from jmbase import chunks
@ -63,7 +63,7 @@ def make_wallets(n,
fixed_seeds=None,
test_wallet=False,
passwords=None,
walletclass=SegwitWallet):
walletclass=None):
'''n: number of wallets to be created
wallet_structure: array of n arrays , each subarray
specifying the number of addresses to be populated with coins
@ -85,7 +85,11 @@ def make_wallets(n,
if test_wallet:
w = TestWallet(seeds[i], max_mix_depth=5, pwd=passwords[i])
else:
w = walletclass(seeds[i], pwd=None, max_mix_depth=5)
if walletclass:
wc = walletclass
else:
wc = get_wallet_cls()
w = wc(seeds[i], pwd=None, max_mix_depth=5)
wallets[i + start_index] = {'seed': seeds[i],
'wallet': w}
for j in range(5):

Loading…
Cancel
Save