From 8b1e24e20a28b0b2ca3e6af1a6fa4739d944b006 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Fri, 27 Sep 2019 17:33:08 +0200 Subject: [PATCH] Make yg algorithms easier to define. This refactors YieldGeneratorBasic a bit. In particular, we move things that custom algorithms will most likely want to change to separate functions. That way, it is easy to define the behaviour of inputs and outputs for the join without the need to duplicate the other, more general logic of create_my_orders and oid_to_order. --- jmclient/jmclient/yieldgenerator.py | 49 ++++++++++++++++++++--------- scripts/yg-privacyenhanced.py | 4 +-- scripts/yield-generator-basic.py | 4 +-- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/jmclient/jmclient/yieldgenerator.py b/jmclient/jmclient/yieldgenerator.py index 7395af8..6214d45 100644 --- a/jmclient/jmclient/yieldgenerator.py +++ b/jmclient/jmclient/yieldgenerator.py @@ -17,7 +17,6 @@ from .wallet_utils import open_test_wallet_maybe, get_wallet_path jlog = get_log() -MAX_MIX_DEPTH = 5 class YieldGenerator(Maker): """A maker for the purposes of generating a yield from held @@ -77,12 +76,11 @@ class YieldGeneratorBasic(YieldGenerator): super(YieldGeneratorBasic,self).__init__(wallet) def create_my_orders(self): - mix_balance = self.wallet.get_balance_by_mixdepth(verbose=False) + mix_balance = self.get_available_mixdepths() if len([b for m, b in iteritems(mix_balance) if b > 0]) == 0: jlog.error('do not have any coins left') return [] - # print mix_balance max_mix = max(mix_balance, key=mix_balance.get) f = '0' if self.ordertype in ('reloffer', 'swreloffer'): @@ -113,23 +111,24 @@ class YieldGeneratorBasic(YieldGenerator): def oid_to_order(self, offer, amount): total_amount = amount + offer["txfee"] - mix_balance = self.wallet.get_balance_by_mixdepth() - max_mix = max(mix_balance, key=mix_balance.get) + mix_balance = self.get_available_mixdepths() - filtered_mix_balance = [m - for m in iteritems(mix_balance) - if m[1] >= total_amount] + filtered_mix_balance = {m: b + for m, b in iteritems(mix_balance) + if b >= total_amount} if not filtered_mix_balance: return None, None, None jlog.debug('mix depths that have enough = ' + str(filtered_mix_balance)) - filtered_mix_balance = sorted(filtered_mix_balance, key=lambda x: x[0]) - mixdepth = filtered_mix_balance[0][0] + mixdepth = self.select_input_mixdepth(filtered_mix_balance, offer, amount) + if mixdepth is None: + return None, None, None jlog.info('filling offer, mixdepth=' + str(mixdepth) + ', amount=' + str(amount)) - # mixdepth is the chosen depth we'll be spending from - cj_addr = self.wallet.get_internal_addr( - (mixdepth + 1) % (self.wallet.mixdepth + 1), - jm_single().bc_interface) + cj_addr = self.select_output_address(mixdepth, offer, amount) + if cj_addr is None: + return None, None, None + jlog.info('sending output to address=' + str(cj_addr)) + change_addr = self.wallet.get_internal_addr(mixdepth, jm_single().bc_interface) @@ -165,6 +164,28 @@ class YieldGeneratorBasic(YieldGenerator): confirm_time / 60.0, 2), '']) return self.on_tx_unconfirmed(offer, txid, None) + def get_available_mixdepths(self): + """Returns the mixdepth/balance dict from the wallet that contains + all available inputs for offers.""" + return self.wallet.get_balance_by_mixdepth(verbose=False) + + def select_input_mixdepth(self, available, offer, amount): + """Returns the mixdepth from which the given order should spend the + inputs. available is a mixdepth/balance dict of all the mixdepths + that can be chosen from, i.e. have enough balance. If there is no + suitable input, the function can return None to abort the order.""" + available = sorted(iteritems(available), key=lambda entry: entry[0]) + return available[0][0] + + def select_output_address(self, input_mixdepth, offer, amount): + """Returns the address to which the mixed output should be sent for + an order spending from the given input mixdepth. Can return None if + there is no suitable output, in which case the order is + aborted.""" + cjoutmix = (input_mixdepth + 1) % (self.wallet.mixdepth + 1) + return self.wallet.get_internal_addr(cjoutmix, jm_single().bc_interface) + + def ygmain(ygclass, txfee=1000, cjfee_a=200, cjfee_r=0.002, ordertype='swreloffer', nickserv_password='', minsize=100000, gaplimit=6): import sys diff --git a/scripts/yg-privacyenhanced.py b/scripts/yg-privacyenhanced.py index aa783a5..29ad96c 100644 --- a/scripts/yg-privacyenhanced.py +++ b/scripts/yg-privacyenhanced.py @@ -35,12 +35,10 @@ jlog = get_log() class YieldGeneratorPrivacyEnhanced(YieldGeneratorBasic): def __init__(self, wallet, offerconfig): - self.txfee, self.cjfee_a, self.cjfee_r, self.ordertype, self.minsize \ - = offerconfig super(YieldGeneratorPrivacyEnhanced, self).__init__(wallet, offerconfig) def create_my_orders(self): - mix_balance = self.wallet.get_balance_by_mixdepth() + mix_balance = self.get_available_mixdepths(verbose=False) # We publish ONLY the maximum amount and use minsize for lower bound; # leave it to oid_to_order to figure out the right depth to use. f = '0' diff --git a/scripts/yield-generator-basic.py b/scripts/yield-generator-basic.py index 9dee2d2..0b76306 100644 --- a/scripts/yield-generator-basic.py +++ b/scripts/yield-generator-basic.py @@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function, unicode_literals) from builtins import * # noqa: F401 -from jmbase import get_log, jmprint +from jmbase import jmprint from jmclient import YieldGeneratorBasic, ygmain """THESE SETTINGS CAN SIMPLY BE EDITED BY HAND IN THIS FILE: @@ -16,8 +16,6 @@ nickserv_password = '' max_minsize = 100000 gaplimit = 6 -jlog = get_log() - if __name__ == "__main__": ygmain(YieldGeneratorBasic, txfee=txfee, cjfee_a=cjfee_a, cjfee_r=cjfee_r, ordertype=ordertype,