Browse Source

fix up sweeps, now working

master
Adam Gibson 9 years ago
parent
commit
e38218c011
No known key found for this signature in database
GPG Key ID: B3AE09F1E9A3197A
  1. 16
      jmclient/support.py
  2. 102
      jmclient/taker.py

16
jmclient/support.py

@ -275,9 +275,9 @@ def choose_orders(offers, cj_amount, n, chooseOrdersBy, ignored_makers=None):
return result, total_cj_fee return result, total_cj_fee
def choose_sweep_orders(db, def choose_sweep_orders(offers,
total_input_value, total_input_value,
txfee, total_txfee,
n, n,
chooseOrdersBy, chooseOrdersBy,
ignored_makers=None): ignored_makers=None):
@ -291,7 +291,6 @@ def choose_sweep_orders(db,
=> 0 = totalin - mytxfee - sum(absfee) - cjamount*(1 + sum(relfee)) => 0 = totalin - mytxfee - sum(absfee) - cjamount*(1 + sum(relfee))
=> cjamount = (totalin - mytxfee - sum(absfee)) / (1 + sum(relfee)) => cjamount = (totalin - mytxfee - sum(absfee)) / (1 + sum(relfee))
""" """
total_txfee = txfee * n
if ignored_makers is None: if ignored_makers is None:
ignored_makers = [] ignored_makers = []
@ -317,14 +316,13 @@ def choose_sweep_orders(db,
log.debug('choosing sweep orders for total_input_value = ' + str( log.debug('choosing sweep orders for total_input_value = ' + str(
total_input_value) + ' n=' + str(n)) total_input_value) + ' n=' + str(n))
sqlorders = db.execute('SELECT * FROM orderbook WHERE minsize <= ?;', #Filter ignored makers and inappropriate amounts
(total_input_value,)).fetchall() offers = [o for o in offers if o['counterparty'] not in ignored_makers]
orderlist = [dict([(k, o[k]) for k in ORDER_KEYS]) offers = [o for o in offers if o['minsize'] < total_input_value]
for o in sqlorders if o['counterparty'] not in ignored_makers]
log.debug('orderlist = \n' + '\n'.join([str(o) for o in orderlist])) log.debug('orderlist = \n' + '\n'.join([str(o) for o in offers]))
orders_fees = [(o, calc_cj_fee(o['ordertype'], o['cjfee'], orders_fees = [(o, calc_cj_fee(o['ordertype'], o['cjfee'],
total_input_value)) for o in orderlist] total_input_value)) for o in offers]
feekey = lambda x: x[1] feekey = lambda x: x[1]
# sort from smallest to biggest cj fee # sort from smallest to biggest cj fee

102
jmclient/taker.py

@ -11,7 +11,8 @@ import copy
import btc import btc
from jmclient.configure import jm_single, get_p2pk_vbyte, donation_address from jmclient.configure import jm_single, get_p2pk_vbyte, donation_address
from jmbase.support import get_log from jmbase.support import get_log
from jmclient.support import calc_cj_fee, weighted_order_choose, choose_orders from jmclient.support import (calc_cj_fee, weighted_order_choose, choose_orders,
choose_sweep_orders)
from jmclient.wallet import estimate_tx_fee from jmclient.wallet import estimate_tx_fee
from jmclient.podle import (generate_podle, get_podle_commitments, from jmclient.podle import (generate_podle, get_podle_commitments,
PoDLE, PoDLEError, generate_podle_error_string) PoDLE, PoDLEError, generate_podle_error_string)
@ -122,7 +123,8 @@ class Taker(object):
self.txfee_default = 5000 self.txfee_default = 5000
self.txid = None self.txid = None
if not self.filter_orderbook(orderbook): sweep = True if self.cjamount == 0 else False
if not self.filter_orderbook(orderbook, sweep):
return (False,) return (False,)
#choose coins to spend #choose coins to spend
if not self.prepare_my_bitcoin_data(): if not self.prepare_my_bitcoin_data():
@ -136,26 +138,26 @@ class Taker(object):
self.taker_info_callback("INFO", errmsg) self.taker_info_callback("INFO", errmsg)
return (True, self.cjamount, commitment, revelation, self.orderbook) return (True, self.cjamount, commitment, revelation, self.orderbook)
def filter_orderbook(self, orderbook): def filter_orderbook(self, orderbook, sweep=False):
self.orderbook, self.total_cj_fee = choose_orders( if sweep:
orderbook, self.cjamount, self.n_counterparties, self.order_chooser, self.orderbook = orderbook #offers choosing deferred to next step
self.ignored_makers) else:
if self.filter_orders_callback: self.orderbook, self.total_cj_fee = choose_orders(
accepted = self.filter_orders_callback([self.orderbook, orderbook, self.cjamount, self.n_counterparties, self.order_chooser,
self.total_cj_fee]) self.ignored_makers)
if not accepted: if self.filter_orders_callback:
return False accepted = self.filter_orders_callback([self.orderbook,
self.total_cj_fee])
if not accepted:
return False
return True return True
def prepare_my_bitcoin_data(self): def prepare_my_bitcoin_data(self):
"""Get a coinjoin address and a change address; prepare inputs """Get a coinjoin address and a change address; prepare inputs
appropriate for this transaction""" appropriate for this transaction"""
if not self.my_cj_addr: if not self.my_cj_addr:
try: #previously used for donations; TODO reimplement?
self.my_cj_addr = self.wallet.get_external_addr(self.mixdepth + 1) raise NotImplementedError
except:
self.taker_info_callback("ABORT", "Failed to get an address")
return False
self.my_change_addr = None self.my_change_addr = None
if self.cjamount != 0: if self.cjamount != 0:
try: try:
@ -163,22 +165,58 @@ class Taker(object):
except: except:
self.taker_info_callback("ABORT", "Failed to get a change address") self.taker_info_callback("ABORT", "Failed to get a change address")
return False return False
#TODO sweep, doesn't apply here self.total_txfee = 2 * self.txfee_default * self.n_counterparties
self.total_txfee = 2 * self.txfee_default * self.n_counterparties total_amount = self.cjamount + self.total_cj_fee + self.total_txfee
total_amount = self.cjamount + self.total_cj_fee + self.total_txfee jlog.debug('total estimated amount spent = ' + str(total_amount))
jlog.debug('total estimated amount spent = ' + str(total_amount)) #adjust the required amount upwards to anticipate an increase in
#adjust the required amount upwards to anticipate an increase in #transaction fees after re-estimation; this is sufficiently conservative
#transaction fees after re-estimation; this is sufficiently conservative #to make failures unlikely while keeping the occurence of failure to
#to make failures unlikely while keeping the occurence of failure to #find sufficient utxos extremely rare. Indeed, a doubling of 'normal'
#find sufficient utxos extremely rare. Indeed, a doubling of 'normal' #txfee indicates undesirable behaviour on maker side anyway.
#txfee indicates undesirable behaviour on maker side anyway. try:
try: self.input_utxos = self.wallet.select_utxos(self.mixdepth,
self.input_utxos = self.wallet.select_utxos(self.mixdepth, total_amount)
total_amount) except Exception as e:
except Exception as e: self.taker_info_callback("ABORT",
self.taker_info_callback("ABORT", "Unable to select sufficient coins: " + repr(e))
"Unable to select sufficient coins: " + repr(e)) return False
return False else:
#sweep
self.input_utxos = self.wallet.get_utxos_by_mixdepth()[self.mixdepth]
#do our best to estimate the fee based on the number of
#our own utxos; this estimate may be significantly higher
#than the default set in option.txfee * makercount, where
#we have a large number of utxos to spend. If it is smaller,
#we'll be conservative and retain the original estimate.
est_ins = len(self.input_utxos)+3*self.n_counterparties
jlog.debug("Estimated ins: "+str(est_ins))
est_outs = 2*self.n_counterparties + 1
jlog.debug("Estimated outs: "+str(est_outs))
estimated_fee = estimate_tx_fee(est_ins, est_outs)
jlog.info("We have a fee estimate: "+str(estimated_fee))
jlog.info("And a requested fee of: "+str(
self.txfee_default * self.n_counterparties))
self.total_txfee = max([estimated_fee,
self.n_counterparties * self.txfee_default])
total_value = sum([va['value'] for va in self.input_utxos.values()])
self.orderbook, self.cjamount, self.total_cj_fee = choose_sweep_orders(
self.orderbook, total_value, self.total_txfee,
self.n_counterparties, self.order_chooser,
self.ignored_makers)
if not self.orderbook:
self.taker_info_callback("ABORT",
"Could not find orders to complete transaction")
self.on_finished_callback(False)
return False
if not self.answeryes:
jlog.info('total cj fee = ' + str(self.total_cj_fee))
total_fee_pc = 1.0 * self.total_cj_fee / self.cjamount
jlog.info('total coinjoin fee = ' + str(float('%.3g' % (
100.0 * total_fee_pc))) + '%')
if raw_input('send with these orders? (y/n):')[0] != 'y':
self.on_finished_callback(False)
return False
self.utxos = {None: self.input_utxos.keys()} self.utxos = {None: self.input_utxos.keys()}
return True return True

Loading…
Cancel
Save