Skip to content
This repository has been archived by the owner on May 13, 2022. It is now read-only.

Incentivise Network Diversity #362

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 6 additions & 5 deletions joinmarket/irc.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ def get_irc_text(line):
return line[line[1:].find(':') + 2:]


def get_irc_nick(source):
return source[1:source.find('!')]
def get_irc_nick(source): # Sybil annoyance through hostmask inclusion
return source[1:source.find('!') + 1] + source[source.find('@') + 1:]


class PingThread(threading.Thread):
Expand Down Expand Up @@ -143,8 +143,9 @@ def push_tx(self, nick, txhex):
def announce_orders(self, orderlist, nick=None):
# nick=None means announce publicly
order_keys = ['oid', 'minsize', 'maxsize', 'txfee', 'cjfee']
header = 'PRIVMSG ' + (nick if nick else self.channel) + ' :'
orderlines = []
target = nick[:nick.find('!')] if nick else self.channel # same header
header = 'PRIVMSG ' + target + ' :' # works for both pit announcements
orderlines = [] # and PM replies to !orderbook
for i, order in enumerate(orderlist):
orderparams = COMMAND_PREFIX + order['ordertype'] + \
' ' + ' '.join([str(order[k]) for k in order_keys])
Expand Down Expand Up @@ -192,7 +193,7 @@ def __privmsg(self, nick, cmd, message):
return
message = encrypt_encode(message, box)

header = "PRIVMSG " + nick + " :"
header = "PRIVMSG " + nick[:nick.find('!')] + " :" # remove hostmask
max_chunk_len = MAX_PRIVMSG_LEN - len(header) - len(cmd) - 4
# 1 for command prefix 1 for space 2 for trailer
if len(message) > max_chunk_len:
Expand Down
48 changes: 25 additions & 23 deletions joinmarket/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,14 @@ def pick_order(orders, n, feekey):
return orders[pickedOrderIndex]
pickedOrderIndex = -1

def offer_profit(offer):
"""
Calculates the net profit to the maker of the given offer.
Expects an offer in the form (counterparty, oid, cjfee, txfee)
where cjfee and txfee are integer amounts of satoshi.
"""
return offer[2] - offer[3]


def choose_orders(db, cj_amount, n, chooseOrdersBy, ignored_makers=None):
if ignored_makers is None:
Expand All @@ -246,10 +254,20 @@ def choose_orders(db, cj_amount, n, chooseOrdersBy, ignored_makers=None):
if o['minsize'] <= cj_amount <= o['maxsize'] and o[
'counterparty'] not in ignored_makers]

# function that returns the fee for a given order
def feekey(o):
return o[2] - o[3]
"""
restrict to one order per counterparty, choose the one with the lowest
cjfee this is done in advance of the order selection algo, so applies to
all of them. however, if orders are picked manually, allow duplicates.
"""
if chooseOrdersBy != pick_order:
orders = sorted( # index by hostmask only, as it's harder to
dict(((v[0])[v[0].find('!')+1:], v) # spoof than the nick field
for v in sorted(orders, key=offer_profit,
reverse=True)).values(), key=offer_profit)
else:
orders = sorted(orders, key=offer_profit) # sort by increasing cjfee

# after deduplication, ensure we have enough distinct counterparties
counterparties = set([o[0] for o in orders])
if n > len(counterparties):
log.debug(('ERROR not enough liquidity in the orderbook n=%d '
Expand All @@ -258,24 +276,11 @@ def feekey(o):
# TODO handle not enough liquidity better, maybe an Exception
return None, 0

"""
restrict to one order per counterparty, choose the one with the lowest
cjfee this is done in advance of the order selection algo, so applies to
all of them. however, if orders are picked manually, allow duplicates.
"""
if chooseOrdersBy != pick_order:
orders = sorted(
dict((v[0], v) for v in sorted(
orders, key=feekey, reverse=True)).values(), key=feekey)
else:
orders = sorted(orders,
key=feekey) # sort from smallest to biggest cj fee

log.debug('considered orders = \n' + '\n'.join([str(o) for o in orders]))
total_cj_fee = 0
chosen_orders = []
for i in range(n):
chosen_order = chooseOrdersBy(orders, n, feekey)
chosen_order = chooseOrdersBy(orders, n, offer_profit)
orders = [o for o in orders if o[0] != chosen_order[0]
] # remove all orders from that same counterparty
chosen_orders.append(chosen_order)
Expand All @@ -302,7 +307,7 @@ def choose_sweep_orders(db,
=> cjamount = (totalin - mytxfee - sum(absfee)) / (1 + sum(relfee))
"""
total_txfee = txfee*n

if ignored_makers is None:
ignored_makers = []

Expand Down Expand Up @@ -344,19 +349,16 @@ def calc_zero_change_cj_amount(ordercombo):
total_input_value), o['txfee'])
for o in orderlist]

def feekey(o):
return o[2] - o[3]

# sort from smallest to biggest cj fee
available_orders = sorted(available_orders, key=feekey)
available_orders = sorted(available_orders, key=offer_profit)
chosen_orders = []
while len(chosen_orders) < n:
if len(available_orders) < n - len(chosen_orders):
log.debug('ERROR not enough liquidity in the orderbook')
# TODO handle not enough liquidity better, maybe an Exception
return None, 0
for i in range(n - len(chosen_orders)):
chosen_order = chooseOrdersBy(available_orders, n, feekey)
chosen_order = chooseOrdersBy(available_orders, n, offer_profit)
log.debug('chosen = ' + str(chosen_order))
# remove all orders from that same counterparty
available_orders = [
Expand Down
10 changes: 3 additions & 7 deletions ob-watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,28 +107,24 @@ def get_graph_html(fig):


# callback functions for displaying order data
def do_nothing(arg, order, btc_unit, rel_unit):
return arg

def trim_host(nickhost, order, btc_unit, rel_unit):
return nickhost[nickhost.find('!')+1:]

def ordertype_display(ordertype, order, btc_unit, rel_unit):
ordertypes = {'absorder': 'Absolute Fee', 'relorder': 'Relative Fee'}
return ordertypes[ordertype]


def cjfee_display(cjfee, order, btc_unit, rel_unit):
if order['ordertype'] == 'absorder':
return satoshi_to_unit(cjfee, order, btc_unit, rel_unit)
elif order['ordertype'] == 'relorder':
return str(float(cjfee) * rel_unit_to_factor[rel_unit]) + rel_unit


def satoshi_to_unit(sat, order, btc_unit, rel_unit):
power = unit_to_power[btc_unit]
return ("%." + str(power) + "f") % float(
Decimal(sat) / Decimal(10 ** power))


def order_str(s, order, btc_unit, rel_unit):
return str(s)

Expand All @@ -139,7 +135,7 @@ def create_orderbook_table(db, btc_unit, rel_unit):
if not rows:
return 0, result
order_keys_display = (('ordertype', ordertype_display),
('counterparty', do_nothing), ('oid', order_str),
('counterparty', trim_host), ('oid', order_str),
('cjfee', cjfee_display), ('txfee', satoshi_to_unit),
('minsize', satoshi_to_unit),
('maxsize', satoshi_to_unit))
Expand Down