From 044bef6fffd9d33a1a170ccdec82b9fb48c65df3 Mon Sep 17 00:00:00 2001 From: Adam Gibson Date: Thu, 21 Apr 2022 12:54:48 +0100 Subject: [PATCH] Change default fidelity bond exponent settings. Closes #1247. This consists of an inclusion of the bond value exponent into the config that the user can alter, and a change of that from 2 to default 1.3. Also updates the fidelity bond documentation to account for those changes, including the units used in ob-watcher, but not the calculation of fidelity bond attack resistance (which remains a TODO). --- docs/fidelity-bonds.md | 20 +++++++++++--------- jmclient/jmclient/configure.py | 5 +++++ jmclient/jmclient/wallet.py | 3 ++- scripts/obwatch/ob-watcher.py | 20 ++++++++++++++++---- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/docs/fidelity-bonds.md b/docs/fidelity-bonds.md index 216321adc..cb2d9865c 100644 --- a/docs/fidelity-bonds.md +++ b/docs/fidelity-bonds.md @@ -45,7 +45,7 @@ high enough (or if you think the sybil protection is too expensive then set the lower, as always its your choice as a taker in the market). Takers will still choose makers equally (i.e. without taking into account fidelity bonds) with a -small probability. By default this probability is 12.5%, so approximately 1-in-8 makers. This can +small probability. By default this probability is currently 12.5%, so approximately 1-in-8 makers. This can be changed in the config file with the option `bondless_makers_allowance`. The previous algorithm for choosing makers without regards to fidelity bonds can still be used by @@ -179,12 +179,14 @@ JoinMarket itself. A fidelity bond is valuable as soon as the transaction creating it becomes confirmed. The simplified formula for a fidelity bond's value is: - bond_value = (locked_coins * (exp(interest_rate * locktime) - 1))^2 + bond_value = (locked_coins * (exp(interest_rate * locktime) - 1))^x + +Here `x` is the 'exponent', a number larger than 1, for reasons we explain below. A few important things to notice: -* The bond value goes as the _square_ of sacrificed value. For example if your sacrificed value is -5 BTC then the fidelity bond value is 25 (because 5 x 5 = 25). If instead you sacrificed 6 BTC the -value is 36 (because 6 x 6 = 36). The point of this is to create an incentive for makers to lump +* The bond value goes as the (locked_coins)^x of sacrificed value. For example if `x` is 1.3, the current default, and your sacrificed value is +5 BTC then the fidelity bond value is \~ 8.1. If instead you sacrificed 6 BTC the +value is \~ 10.3. The point of this is to create an incentive for makers to lump all their coins into just one bot rather than spreading it over many bots. It makes a sybil attack much more expensive. * The longer you lock for the greater the value. The value increases as the `interest_rate`, which @@ -193,9 +195,9 @@ annum and because of tyranny-of-the-default takers are unlikely to change it. Th not too far from the "real" interest rate, and the system still works fine even if the real rate is something like 3% or 0.1%. * The above formula would suggest that if you lock 3 BTC for 10000 years you get a fidelity -bond worth `1.7481837557171304e+131` (17 followed by 130 zeros). This does not happen because the +bond worth `2.03e+85` (\~ 2 followed by 85 zeros). This does not happen because the sacrificed value is capped at the value of the burned coins. So in this example the fidelity bond -value would be just 9 (equal to 3x3 or 3 squared). This feature is not included in the above +value would be just \~ 4.17. This feature is not included in the above simplified equation. * After the locktime expires and the coins are free to move, the fidelity bond will continue to be valuable, but its value will exponentially drop following the interest rate. So it would be good @@ -210,8 +212,8 @@ At any time you can use the orderbook watcher script to see your own fidelity bo Consider also the [warning on the bitcoin wiki page on timelocks](https://en.bitcoin.it/wiki/Timelock#Far-future_locks). -I would recommend locking as many bitcoins as you are comfortable with for a period of between 6 -months and 2 years. Perhaps at the very start lock for only 1 month or 2 months(?) It's a +I would recommend locking as many bitcoins as you are comfortable with for a period of between 3 +months and 1 years. Perhaps at the very start lock for only 1 month or 2 months(?) It's a marketplace and the rules are known to all, so ultimately you'll have to make your own decision. ### Can my yield-generator use multiple timelocked addresses or UTXO? diff --git a/jmclient/jmclient/configure.py b/jmclient/jmclient/configure.py index eeffc7e4a..daef3b50a 100644 --- a/jmclient/jmclient/configure.py +++ b/jmclient/jmclient/configure.py @@ -386,6 +386,11 @@ def jm_single(): # A real number, i.e. 1 = 100%, 0.125 = 1/8 = 1 in every 8 makers on average will be bondless bondless_makers_allowance = """ + _DEFAULT_BONDLESS_MAKERS_ALLOWANCE + """ +# To (strongly) disincentivize Sybil behaviour, the value assessment of the bond +# is based on the (time value of the bond)^x where x is the bond_value_exponent here, +# where x > 1. It is a real number (so written as a decimal). +bond_value_exponent = 1.3 + ############################## # THE FOLLOWING SETTINGS ARE REQUIRED TO DEFEND AGAINST SNOOPERS. # DON'T ALTER THEM UNLESS YOU UNDERSTAND THE IMPLICATIONS. diff --git a/jmclient/jmclient/wallet.py b/jmclient/jmclient/wallet.py index 3eea14068..1938f14a1 100644 --- a/jmclient/jmclient/wallet.py +++ b/jmclient/jmclient/wallet.py @@ -2557,7 +2557,8 @@ def calculate_timelocked_fidelity_bond_value(cls, utxo_value, confirmation_time, t = current_time / YEAR a = max(0, min(1, exp(r*T) - 1) - min(1, exp(r*max(0, t-L)) - 1)) - return utxo_value*utxo_value*a*a + exponent = float(jm_single().config.get("POLICY", "bond_value_exponent")) + return pow(utxo_value*a, exponent) @classmethod def get_validated_timelocked_fidelity_bond_utxo(cls, utxo, utxo_pubkey, locktime, diff --git a/scripts/obwatch/ob-watcher.py b/scripts/obwatch/ob-watcher.py index 7835feb17..a156ccf6e 100755 --- a/scripts/obwatch/ob-watcher.py +++ b/scripts/obwatch/ob-watcher.py @@ -51,6 +51,8 @@ import jmbitcoin as btc from jmdaemon.protocol import * +bond_exponent = None + #Initial state: allow only SW offer types sw0offers = list(filter(lambda x: x[0:3] == 'sw0', offername_list)) swoffers = list(filter(lambda x: x[0:3] == 'swa' or x[0:3] == 'swr', offername_list)) @@ -115,7 +117,7 @@ def create_offerbook_table_heading(btc_unit, rel_unit): col.format('txfee', 'Miner Fee Contribution / ' + btc_unit), col.format('minsize', 'Minimum Size / ' + btc_unit), col.format('maxsize', 'Maximum Size / ' + btc_unit), - col.format('bondvalue', 'Bond value / ' + btc_unit + '²') + col.format('bondvalue', 'Bond value / ' + btc_unit + '' + bond_exponent + '') ]) + ' ' return tableheading @@ -123,7 +125,7 @@ def create_bonds_table_heading(btc_unit): tableheading = ('' + '' + '' - + '' + + '' + '' + '' + '' @@ -419,7 +421,8 @@ def create_sybil_resistance_page(self, btc_unit): + "how much would a sybil attacker starting now have to sacrifice to succeed in their" + " attack with 95% probability. Honest weight=" + satoshi_to_unit_power(honest_weight, 2*unit_to_power[btc_unit]) + " " + btc_unit - + "²
Also assumes that takers are not price-sensitive and that their max " + + "" + bond_exponent + "
Also assumes that takers " + + "are not price-sensitive and that their max " + "coinjoin fee is configured high enough that they dont exclude any makers.") heading2 = "Sybil attacks from external enemies." @@ -459,7 +462,7 @@ def create_sybil_resistance_page(self, btc_unit): mainbody += ('
CounterpartyUTXOBond value / ' + btc_unit + '²Bond value / ' + btc_unit + '' + bond_exponent + 'LocktimeLocked coins / ' + btc_unit + 'Confirmation time
' + '' + '' - + '' + + '' + '' ) @@ -784,6 +787,7 @@ def get_dummy_nick(): return nick def main(): + global bond_exponent parser = OptionParser( usage='usage: %prog [options]', description='Runs a webservice which shows the orderbook.') @@ -804,6 +808,14 @@ def main(): default=62601) (options, args) = parser.parse_args() load_program_config(config_path=options.datadir) + # needed to display notional units of FB valuation + bond_exponent = jm_single().config.get("POLICY", "bond_value_exponent") + try: + float(bond_exponent) + except ValueError: + log.error("Invalid entry for bond_value_exponent, should be decimal " + "number: {}".format(bond_exponent)) + sys.exit(EXIT_FAILURE) check_and_start_tor() hostport = (options.host, options.port) mcs = []
Maker countSuccess probabilityForegone value / ' + btc_unit + '²Foregone value / ' + btc_unit + '' + bond_exponent + '