-
Notifications
You must be signed in to change notification settings - Fork 119
Sourcing commitments for joins
This guide is for Joinmarket 0.2+ ; it is not relevant for earlier versions.
To keep reading time short, what to do and what not to do is in bold, so you can focus on that.
To reduce the potential for spying, we now require that every request for a coinjoin comes along with a "commitment" which is a hash value based on the idea of proof of discrete log equivence, PoDLE.
The gory crypto details don't matter of course, what matters is that for each utxo you own that is (a) at least 5 blocks old, and (b) contains an amount of at least 20% of the transaction size("20%" is controlled by taker_utxo_amtpercent
in joinmarket.cfg
- don't change this), you are allowed 3 tries ("3" is controlled by taker_utxo_retries
in joinmarket.cfg
- don't change this) to do a transaction. Once you've tried 3 times, you have to use a different utxo (some Makers may choose to be more lax, but this will be the usual requirement).
Usually they will be sourced from your Joinmarket wallet, and this will require no intervention. The main purpose of this page is (a) to make that happen as much as possible and (b) to tell you what to do if it goes wrong.
Commitments will not be accepted if the age is less than the default 5 confirmations, so for a fresh wallet, wait for at least 5 blocks before starting as a user/taker.
To help, when you fund your Joinmarket wallet (as a Taker, i.e. a transaction originator using sendpayment
or tumbler
; for Makers it doesn't matter), it's recommended to send the coins to multiple (e.g. 3) addresses. In wallets like Bitcoin Core or Electrum (or I presume many others) this can be done in the GUI using the sendtomany
or paytomany
feature; you just enter multiple addresses (and probably pay the same amount to each one). If you're using Joinmarket sendpayment, you'll want to choose several receiving addresses in one external branch for one mixdepth. Don't do a sendtomany
to different mixdepths, as that will link those mixdepths together, a central thing that Joinmarket avoids. Also, don't send multiple outputs to the same address - use different addresses.
As an example, if you send to 3 address instead of 1, you will then have 9 commiments available - effectively 9 tries at doing the first transaction, instead of only 3 tries if you send the coins to one address.
However, don't split an amount to be spent into > 5 - because a utxo has to be at least 20% of the total payment amount, so you could find yourself unable to source a commitment in that case. 3 equal sized amounts ought to be fine.
In most cases this will be enough.
Because of the way the tumbler algorithm works, your utxos will get "used up" as coins are swept from one depth to the next, so it's nearly inevitable that at some point, the utxos you have are too new (<5 blocks) to provide a valid commitment. For this reason, the code now waits until you have a valid commitment in the wallet (see the switch jm_single().wait_for_commitments = 1
in the tumbler.py code). This will mean that you can't run the tumbler relatively fast, e.g. if you did a run that should take around 4 hours, it might take several hours longer. If you use default or slower waits, it might not make any observable difference.
However, it's possible to be more impatient, although there are caveats - see the next section.
In cases where you don't have enough utxos with valid commitments left, or you're not prepared to wait 5 blocks, there are alternatives made available. If you go into the cmttools
directory you'll find a tool add-utxo.py
. Run python add-utxo.py --help
to see an explanation. In short, you can:
- Add external utxos from a non-JM wallet, like Electrum or Core, one at a time, or from a prepared file (-r).
- Add external utxos from another Joinmarket wallet (-w).
- Delete existing external utxos (-d)
- Validate utxos (-v, -o)
Note that "adding a utxo" does not mean spending it! It only means adding a hash-value commitment and the pubkey, basically. Any Bitcoin utxo can be used as an effective 3-time usage token, without spending it.
Be aware that Makers will see this utxo only if your usage is successful (they accept it and return their utxos in response), which is a reason not to use this "sourcing external" approach if you have any concerns about them getting that knowledge. Also, if you source a utxo from another non-JM wallet you will have to pass its private key in WIF compressed format to the script (it cannot be signed inside the wallet as this is not a standard Bitcoin ECDSA signature), in order to create the commitment - the usual strong warnings about handling private keys apply here, so use this approach only very carefully.
The commitments you've already used (just hash values) are stored in the used
section of the file cmttools/commitments.json
- don't delete this file. Although you won't need to read this file, it represents your memory of which commitments you've already used, so if you lose that record, your Taker scripts will find themselves spending a lot of time retrying commitments that the rest of the Joinmarket "network" knows are already used, and so will be rejected. This is only an inconvenience, but it could be pretty annoying. Any external commitments you sourced according to the previous section are also added here, and deleted automatically once they're used up. You can add/delete the contents of that external
section using the previously mentioned cmttools/add-utxo.py
script (see previous section for a brief overview of options).
If in a run of sendpayment.py
no commitment can be sourced (in tumbler it just waits), either within the internal wallet, or external as described above, a file commitments_debug.txt
is created that will show exactly which utxos have been tried and why they failed - and gives brief instructions on what to do depending on the state of each of those. A sample file is shown at the end of this page.
An extra method for wallet-tool.py
is added: showutxos
- this will pretty print the all the available utxos in any Joinmarket wallet. This is only potentially useful for people who run both as Maker and Taker and want to consider transferring utxos for commitments from one wallet to another (using the -w
option to cmttools/add-utxo.py
).
Similarly a sendtomany
function is available in cd cmttools; python sendtomany.py --help
; read the help for details but it's as simple as it sounds, specifically creating equal sized outputs for each of the destination addresses you specify; it requires one utxo and its private key as inputs. You're prompted before broadcast, so you can check its validity.
Sample commitments_debug.txt:
THIS IS A TEMPORARY FILE FOR DEBUGGING; IT CAN BE SAFELY DELETED ANY TIME.
***
1: Utxos that passed age and size limits, but have been used too many times (see taker_utxo_retries in the config):
None
2: Utxos that have less than 5 confirmations:
f8f0256f70ed3b60c2d933a697a8462ccf7d165bbf3d5a33fd4a4ff57eb8cc27:0
ed00d570efc763706bbca3cf008afe9ab50da730f0a428ea0115f7642186ff54:0
ac947720cabab156c41cb9d6ade90c260107dd08584522b703b79433aa877767:1
71b527f7802d2a6694d474b0e5532dfa0abd349a64f163809c93ed6324c9230f:0
aee068c78fa9d576378828f1539fba6027ddb00c2bdb3747b970d21ecbd64f39:1
3: Utxos that were not at least 20% of the size of the coinjoin amount 199164661
None
***
Utxos that appeared in item 1 cannot be used again.
Utxos only in item 2 can be used by waiting for more confirmations, (set by the value of taker_utxo_age).
Utxos only in item 3 are not big enough for this coinjoin transaction, set by the value of taker_utxo_amtpercent.
If you cannot source a utxo from your wallet according to these rules, use the tool add-utxo.py to source a utxo external to your joinmarket wallet. Read the help with 'python add-utxo.py --help'
You can also reset the rules in the joinmarket.cfg file, but this is generally inadvisable.
***
For reference, here are the utxos in your wallet:
{u'f8f0256f70ed3b60c2d933a697a8462ccf7d165bbf3d5a33fd4a4ff57eb8cc27:0': {'value': 100000000, 'address': u'mfv6e3fjmTbBRgTMoLSmcGoykocuLYoctZ'}, u'ed00d570efc763706bbca3cf008afe9ab50da730f0a428ea0115f7642186ff54:0': {'value': 100000000, 'address': u'n3k7HrKj7wA3HZLjUnHyWjHWpkFhzPvodv'}, u'ac947720cabab156c41cb9d6ade90c260107dd08584522b703b79433aa877767:1': {'value': 100000000, 'address': u'muzRPUFFo5LdVF51gR4PeapNrYLikM2JkN'}, u'71b527f7802d2a6694d474b0e5532dfa0abd349a64f163809c93ed6324c9230f:0': {'value': 100000000, 'address': u'muqTeLpF8ANJBXUK3SZbQU9WdyJ4LUVktm'}, u'aee068c78fa9d576378828f1539fba6027ddb00c2bdb3747b970d21ecbd64f39:1': {'value': 100000000, 'address': u'n45s5NXoAo7Qrq1YctdpoBHpAoeaBunF6i'}}