mirror of
https://github.com/JoinMarket-Org/joinmarket-clientserver.git
synced 2026-08-13 12:33:40 +02:00
428 lines
25 KiB
Markdown
428 lines
25 KiB
Markdown
# Fidelity bonds
|
|
|
|
Fidelity bonds are a feature of JoinMarket which improves the resistance to
|
|
sybil attacks, and therefore improves the privacy of the system.
|
|
|
|
A fidelity bond is a mechanism where bitcoin value is deliberately sacrificed
|
|
to make a cryptographic identity expensive to obtain. The sacrifice is done in
|
|
a way that can be proven to a third party. Takers in JoinMarket will
|
|
have a higher probability to create coinjoins with makers who publish more
|
|
valuable fidelity bonds. This has the effect of making the system much more
|
|
expensive to sybil attack, because an attacker would have to sacrifice a lot of
|
|
value in order to be chosen very often by takers when creating coinjoin.
|
|
|
|
As a maker you can take part in many more coinjoins and therefore earn more
|
|
fees if you sacrifice bitcoin value to create a fidelity bond. The most
|
|
practical way to create a fidelity bond is to send bitcoins to a time-locked
|
|
address which uses the opcode [OP_CHECKLOCKTIMEVERIFY](https://en.bitcoin.it/wiki/Timelock#CheckLockTimeVerify).
|
|
The valuable thing being sacrificed is the time-value-of-money. Note that a
|
|
long-term holder (or hodler) of bitcoins can buy time-locked fidelity bonds
|
|
essentially for free, assuming they never intended to transact with their coins
|
|
anyway.
|
|
|
|
The private keys to fidelity bonds can be kept in [cold storage](https://en.bitcoin.it/wiki/Cold_storage)
|
|
for added security. (Note: not implemented in JoinMarket)
|
|
|
|
For a more detailed explanation of how fidelity bonds work see these documents:
|
|
|
|
* [Design for improving JoinMarket's resistance to sybil attacks using fidelity
|
|
bonds](https://gist.github.com/chris-belcher/18ea0e6acdb885a2bfbdee43dcd6b5af/)
|
|
|
|
* [Financial mathematics of JoinMarket fidelity bonds](https://gist.github.com/chris-belcher/87ebbcbb639686057a389acb9ab3e25b)
|
|
|
|
## How to use fidelity bonds as a taker
|
|
|
|
In JoinMarket version v0.9 or later takers will by default use fidelity bonds. The user gains
|
|
very strong protection from sybil attacks without needing to do anything different.
|
|
|
|
The orderbook watcher script now displays information about any fidelity bonds
|
|
advertised by makers, as well as calculating how strong the system is against
|
|
hypothetical sybil attackers.
|
|
|
|
Some makers with high-valued fidelity bonds may choose to ask for a high coinjoin fee, so
|
|
for the strongest protection from sybil attacks make sure to set your maximum coinjoin fee
|
|
high enough (or if you think the sybil protection is too expensive then set the max fee
|
|
lower, as always it's 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 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
|
|
passing the relevant CLI option when running a script (for example
|
|
`python3 sendpayment.py -R wallet.jmdat <amount> <address>`). As always use `--help` to get a full
|
|
list of options.
|
|
|
|
|
|
## How to create and use a fidelity bond as a yield-generator
|
|
|
|
You need to create a fidelity bond wallet and run the yield-generator script on it. In practice the
|
|
vast majority of wallets will contain just a single fidelity bond. If the wallet for some reason
|
|
has multiple fidelity bonds then the yield generator will automatically announce the most valuable
|
|
fidelity bond in its wallet. Fidelity bonds are only supported for native segwit wallets.
|
|
|
|
### Creating a JoinMarket wallet which supports creating a fidelity bond
|
|
|
|
When generating a JoinMarket wallet on the command line, supporting versions
|
|
will offer an option to make the wallet support creating a fidelity bond.
|
|
|
|
(jmvenv) $ python3 wallet-tool.py generate
|
|
Would you like to use a two-factor mnemonic recovery phrase? write 'n' if you don't know what this is (y/n): n
|
|
Not using mnemonic extension
|
|
Enter wallet file encryption passphrase:
|
|
Reenter wallet file encryption passphrase:
|
|
Input wallet file name (default: wallet.jmdat): testfidelity.jmdat
|
|
Would you like this wallet to support fidelity bonds? write 'n' if you don't know what this is (y/n): y
|
|
Write down this wallet recovery mnemonic
|
|
|
|
use amateur twelve unfair weekend file canal frog cotton play renew illegal
|
|
|
|
Generated wallet OK
|
|
|
|
As always, it is crucially important to write down the 12-word [seed phrase](https://en.bitcoin.it/wiki/Seed_phrase)
|
|
as a backup. It is also recommended to write down the name of the creating wallet
|
|
"JoinMarket" and that the fidelity bond option was enabled. Writing the wallet
|
|
creation date is also useful as it can help with rescanning.
|
|
|
|
#### Adding fidelity bond support to an existing wallet
|
|
|
|
On any **native segwit** wallet this can be done by using the `recover` method:
|
|
|
|
(jmvenv) $ python3 wallet-tool.py recover
|
|
|
|
And then choosing `yes` to create a fidelity bond wallet.
|
|
|
|
#### Note on privacy
|
|
|
|
A Bitcoin transaction which creates a fidelity bond will be published to the entire world, so before
|
|
creating them make sure the coins are not linked to any of your privacy-relevant information.
|
|
Perhaps mix with JoinMarket. Also, use a sweep transaction which does not create a change output
|
|
when funding the timelocked address. Change addresses can also leak privacy information and the
|
|
best way to avoid that is to not create change outputs at all i.e. use only sweep transactions.
|
|
|
|
Once the timelocked addresses expire and become spendable, make sure you don't leak any information
|
|
then either, mix afterwards as well. If your timelocked address expires and you want to send the
|
|
coins to another timelocked address then you don't need to mix in between, because no
|
|
privacy-relevant information linked to you has been leaked.
|
|
|
|
This can all be done with `sendpayment.py` and coin control (i.e. freezing the UTXOs that you don't
|
|
want to spend).
|
|
|
|
### Obtaining a time-locked address
|
|
|
|
The `wallet-tool.py` script supports a new method `gettimelockaddress` used for
|
|
obtaining time-locked addresses. If bitcoins are sent to these addresses they will
|
|
be locked up until the timelock date passes. Only mixdepth zero can have a
|
|
fidelity bond in it.
|
|
|
|
This example creates an address which locks any coins sent to it until June 2025.
|
|
|
|
(jmvenv) $ python3 wallet-tool.py testfidelity.jmdat gettimelockaddress 2025-6
|
|
Enter wallet decryption passphrase:
|
|
path = m/84'/1'/0'/2/0:1748736000
|
|
Coins sent to this address will not be spendable until June 2025. Full date: 2025-06-01 00:00:00
|
|
WARNING: You should send coins to this address only once. Only single biggest value UTXO will be announced as a fidelity bond. Sending coins to this address multiple times will not increase fidelity bond value.
|
|
WARNING: Only send coins here which are from coinjoins or otherwise not linked to your identity. Also, use a sweep transaction when funding the timelocked address, i.e. Don't create a change address. See the privacy warnings in fidelity-bonds.md
|
|
bcrt1qvcjcggpcw2rzk4sks94r3nxj5xhgkqm4p9h54c7mtr695se27efqqxnu0k
|
|
|
|
|
|
If coins are sent to these addresses they will appear in the usual `wallet-tool.py`
|
|
display:
|
|
|
|
(jmvenv) $ python3 wallet-tool.py -m 0 testfidelity.jmdat
|
|
Enter wallet decryption passphrase:
|
|
JM wallet
|
|
mixdepth 0 fbonds-mpk-tpubDCv7SSisuV4AqNgRqHcXFAeCjV9Z5SPZgSVFjzydEZrS5Jg1uCkv4wGfMZc3wEaiC2hkEfbD753u4R6Shpgj8bR1kuKnEciB522kSpQ3j1v
|
|
external addresses m/84'/1'/0'/0 tpubDEdbDAFbNCXXN54M2qgzHBJYxkHK9hoeisyRsC2gC3WZuxziU5RkcJWgpw7nJqugPx26Ui9c2AqCy9gwZpgTtL1GW1TuPtKRX2SdrrjBY2W
|
|
m/84'/1'/0'/0/0 bcrt1qwmj5yht2xxr3juxczt453uqjltc3xdyklkjnjt 2.00000000 used
|
|
m/84'/1'/0'/0/1 bcrt1q99nzc6s8fh37rjju8gfws4dcfhrpcfz0jst829 0.00000000 new
|
|
m/84'/1'/0'/0/2 bcrt1ql3fxzq2ueyhm8kwy7du6nsv7fgpvujupd2emms 0.00000000 new
|
|
m/84'/1'/0'/0/3 bcrt1qgxr5mh8v4dj8kuqv98ckjzqdmzd4xjcn539nc6 0.00000000 new
|
|
m/84'/1'/0'/0/4 bcrt1qhyhwzkh60p26pk2v008ejqhcl8g70h5vuw2fn6 0.00000000 new
|
|
m/84'/1'/0'/0/5 bcrt1q9xuzrqql028wpj3933zyny6geg2u75rhaygv6z 0.00000000 new
|
|
m/84'/1'/0'/0/6 bcrt1q8w7ewzl4q8mwxx7erf7pjq36z5g088jxzqjdcn 0.00000000 new
|
|
Balance: 2.00000000
|
|
internal addresses m/84'/1'/0'/1
|
|
Balance: 0.00000000
|
|
internal addresses m/84'/1'/0'/2 tpubDEdbDAFbNCXXSFfUKS5QAaxN9toxv8pFSn3TxRdhEij46wj88RCch7ZBA2fgqsocD7MZqowVAdm6LyYumKuKZbzT4V2CfudwDicrMnqqbjC
|
|
m/84'/1'/0'/2/0:1748736000 bcrt1qvcjcggpcw2rzk4sks94r3nxj5xhgkqm4p9h54c7mtr695se27efqqxnu0k 2.00000000 2025-06-01 [LOCKED]
|
|
Balance: 2.00000000
|
|
internal addresses m/84'/1'/0'/3 tpubDEdbDAFbNCXXUpShWMdtPMDcAogMyZJVAzMMn3wM9rC364sdeUuFMS7ZmdjoMbkf14jeK56uy95UBR2SA9AFFeoVv4j4CqMeaq1tcuBVkZe
|
|
Balance: 0.00000000
|
|
Balance for mixdepth 0: 4.00000000
|
|
|
|
#### Spending time-locked coins
|
|
|
|
Once the time-lock of an address expires the coins can be spent with JoinMarket.
|
|
|
|
Coins living on time-locked addresses are automatically frozen with
|
|
JoinMarket's coin control feature, so before spending you need to unfreeze the
|
|
coins using `python3 wallet-tool.py <walletname> -m 0 freeze`.
|
|
|
|
Once unfrozen and untimelocked the coins can be spent with a **non-coinjoin** transaction with
|
|
`sendpayment.py -N 0`.
|
|
|
|
It is **not** possible to passively spend these untimelocked coins in your yield generator;
|
|
they are auto frozen while the yield generator runs, because their signing scripts are not
|
|
compatible with the current Joinmarket protocol.
|
|
|
|
It is also **not** possible to spend these untimelocked coins in a coinjoin as a taker.
|
|
|
|
It is not *currently* possible to spend these untimelocked coins in a PSBT, until our PSBT code is updated to support these custom scripts.
|
|
|
|
NB You cannot export the private keys (which is always disadvised, anyway)
|
|
of timelocked addresses to any other wallets, as they use custom scripts. You must spend them from
|
|
JoinMarket itself.
|
|
|
|
### What amount of bitcoins to lock up and for how long?
|
|
|
|
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))^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 (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
|
|
is configurable in the config file with the option `interest_rate`. By default it is 1.5% per
|
|
annum and because of tyranny-of-the-default takers are unlikely to change it. This value is probably
|
|
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 `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 \~ 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
|
|
for you as a yield generator to create a transaction with the UTXO spending it to another
|
|
time-locked address, but it's not a huge rush (specifically, there's likely no need to pay massive
|
|
miner fees, you can probably wait until fees are low).
|
|
|
|
The full details on valuing a time-locked fidelity bond are [found in the relevant section of the
|
|
"Financial mathematics of fidelity bonds" document](https://gist.github.com/chris-belcher/87ebbcbb639686057a389acb9ab3e25b#time-locked-fidelity-bonds).
|
|
|
|
To see how valuable a bond would be, and to compare it with the orderbook, you can use the `bond-calculator.py` script.
|
|
|
|
For example (see `-h` option for more):
|
|
|
|
```
|
|
(jmvenv) $ python3 scripts/bond-calculator.py -o /home/user/Downloads/orderbook.json 1btc
|
|
User data location: /home/user/.joinmarket/
|
|
Amount locked: 100000000 (1.00000000 btc)
|
|
Confirmation time: 2022-06-16 17:29:26.849274
|
|
Interest rate: 0.015 (1.5%)
|
|
Exponent: 1.3
|
|
|
|
FIDELITY BOND VALUES (BTC^1.3)
|
|
|
|
See /docs/fidelity-bonds.md for complete formula and more
|
|
|
|
Locktime: 2022-7
|
|
Bond value: 0.0000000001579529
|
|
Weight: 0.00001 (0.00% of all bonds)
|
|
Top 85% of the orderbook by value
|
|
|
|
Locktime: 2022-8
|
|
Bond value: 0.0000000007090171
|
|
Weight: 0.00005 (0.00% of all bonds)
|
|
Top 64% of the orderbook by value
|
|
|
|
Locktime: 2022-9
|
|
Bond value: 0.0000000013980293
|
|
Weight: 0.00010 (0.01% of all bonds)
|
|
Top 59% of the orderbook by value
|
|
|
|
[...snipped...]
|
|
```
|
|
|
|
At any time you can use the [orderbook watcher](orderbook.md) script to see your own fidelity bond value, and to download the orderbook in JSON format (`Export orders`).
|
|
|
|
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 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?
|
|
|
|
Alternatively: Can I add more bitcoins to a fidelity bond that already exists?
|
|
|
|
No. Creating a new transaction which sends more bitcoins to a timelocked address will not add to
|
|
the existing fidelity bond, but instead create a new one. The two fidelity bonds will not be
|
|
combined. A yield-generator only announces a single fidelity bond transaction UTXO, and it choses
|
|
the most valuable one.
|
|
|
|
As a yield-generator, you are generally stuck with the fidelity bond you create until it expires.
|
|
You can still create a new fidelity bond and use that instead, but the old one will be unused. If you want
|
|
to increase the value of a fidelity bond the best way to do that is to wait until it expires and
|
|
then spend from the timelocked address combining with extra UTXOs you want to add, into a new
|
|
timelocked address. You can use JoinMarket's coin control feature to control this.
|
|
|
|
This is one reason why a yield-generator who creates a fidelity bond for the first time should only
|
|
lock up coins for a relatively short time, so that they can try out the whole thing, and don't
|
|
have to wait too long before they add more coins.
|
|
|
|
### Creating watch-only fidelity bond wallets
|
|
|
|
#### Note: Fidelity bond in cold storage cannot be advertised to takers right now. You can create watch-only fidelity bond wallets but cant advertise them yet. This feature is pretty easy to add though, and can be done without changing the JoinMarket protocol.
|
|
|
|
Fidelity bonds can be held on an offline computer in
|
|
[cold storage](https://en.bitcoin.it/wiki/Cold_storage). To do this we create
|
|
a watch-only fidelity bond wallet.
|
|
|
|
When fidelity bonds are displayed in `wallet-tool.py`, their master public key
|
|
is highlighted with a prefix `fbonds-mpk-`.
|
|
|
|
This master public key can be used to create a watch-only wallet using
|
|
`wallet-tool.py`.
|
|
|
|
$ python3 wallet-tool.py createwatchonly fbonds-mpk-tpubDDCbCPdf5wJVGYWB4mZr3E3Lys4NBcEKysrrUrLfhG6sekmrvs6KZNe4i5p5z3FyfwRmKMqB9NWEcEUiTS4LwqfrKPQzhKj6aLihu2EejaU
|
|
Input wallet file name (default: watchonly.jmdat): watchfidelity.jmdat
|
|
Enter wallet file encryption passphrase:
|
|
Reenter wallet file encryption passphrase:
|
|
Done
|
|
|
|
Then the wallet can be displayed like a regular wallet, although only the zeroth
|
|
mixdepth will be shown.
|
|
|
|
$ python3 wallet-tool.py watchfidelity.jmdat
|
|
User data location: .
|
|
Enter wallet decryption passphrase:
|
|
JM wallet
|
|
mixdepth 0 fbonds-mpk-tpubDCv7SSisuV4AqNgRqHcXFAeCjV9Z5SPZgSVFjzydEZrS5Jg1uCkv4wGfMZc3wEaiC2hkEfbD753u4R6Shpgj8bR1kuKnEciB522kSpQ3j1v
|
|
external addresses m/84'/1'/0'/0 tpubDEdbDAFbNCXXN54M2qgzHBJYxkHK9hoeisyRsC2gC3WZuxziU5RkcJWgpw7nJqugPx26Ui9c2AqCy9gwZpgTtL1GW1TuPtKRX2SdrrjBY2W
|
|
m/84'/1'/0'/0/0 bcrt1qwmj5yht2xxr3juxczt453uqjltc3xdyklkjnjt 2.00000000 used
|
|
m/84'/1'/0'/0/1 bcrt1q99nzc6s8fh37rjju8gfws4dcfhrpcfz0jst829 0.00000000 new
|
|
m/84'/1'/0'/0/2 bcrt1ql3fxzq2ueyhm8kwy7du6nsv7fgpvujupd2emms 0.00000000 new
|
|
m/84'/1'/0'/0/3 bcrt1qgxr5mh8v4dj8kuqv98ckjzqdmzd4xjcn539nc6 0.00000000 new
|
|
m/84'/1'/0'/0/4 bcrt1qhyhwzkh60p26pk2v008ejqhcl8g70h5vuw2fn6 0.00000000 new
|
|
m/84'/1'/0'/0/5 bcrt1q9xuzrqql028wpj3933zyny6geg2u75rhaygv6z 0.00000000 new
|
|
m/84'/1'/0'/0/6 bcrt1q8w7ewzl4q8mwxx7erf7pjq36z5g088jxzqjdcn 0.00000000 new
|
|
Balance: 2.00000000
|
|
internal addresses m/84'/1'/0'/1
|
|
Balance: 0.00000000
|
|
internal addresses m/84'/1'/0'/2 tpubDEdbDAFbNCXXSFfUKS5QAaxN9toxv8pFSn3TxRdhEij46wj88RCch7ZBA2fgqsocD7MZqowVAdm6LyYumKuKZbzT4V2CfudwDicrMnqqbjC
|
|
m/84'/1'/0'/2/0:1748736000 bcrt1qvcjcggpcw2rzk4sks94r3nxj5xhgkqm4p9h54c7mtr695se27efqqxnu0k 2.00000000 2025-06-01 [LOCKED]
|
|
Balance: 2.00000000
|
|
internal addresses m/84'/1'/0'/3 tpubDEdbDAFbNCXXUpShWMdtPMDcAogMyZJVAzMMn3wM9rC364sdeUuFMS7ZmdjoMbkf14jeK56uy95UBR2SA9AFFeoVv4j4CqMeaq1tcuBVkZe
|
|
Balance: 0.00000000
|
|
Balance for mixdepth 0: 4.00000000
|
|
|
|
### BIP32 Paths
|
|
|
|
Fidelity bond wallets extend the BIP32 path format to include the locktime
|
|
values. In this example we've got `m/49'/1'/0'/2/0:1583020800` where the
|
|
number after the colon is the locktime value in Unix time.
|
|
|
|
This path can be passed to certain wallet methods like `dumpprivkey`.
|
|
|
|
$ python3 wallet-tool.py -H "m/49'/1'/0'/2/0:1583020800" testfidelity.jmdat dumpprivkey
|
|
Enter wallet decryption passphrase:
|
|
cNEuE5ypNTxVFCyC5iH7u5AQTrddamcUHRPNweiLvmHUWd6XXDkz
|
|
|
|
### Burning coins
|
|
|
|
#### Note: There is no point using this feature. Fidelity bonds in JoinMarket cannot be created by burning coins right now. This feature is here only for historical reasons.
|
|
|
|
Coins can be burned with a special method of the `sendpayment.py` script. Set
|
|
the destination to be `BURN`. Transactions which burn coins must only have one
|
|
input and one output, so use coin control to freeze all coins in the zeroth
|
|
mixdepth except one.
|
|
|
|
$ python3 sendpayment.py -N 0 testfidelity3.jmdat 0 BURN
|
|
User data location: .
|
|
2020-04-07 20:45:25,658 [INFO] Using this min relay fee as tx fee floor: 1000 sat/kvB (1.0 sat/vB)
|
|
Enter wallet decryption passphrase:
|
|
2020-04-07 20:46:50,449 [INFO] Estimated miner/tx fees for this coinjoin amount: 0.0%
|
|
2020-04-07 20:46:50,452 [INFO] Using this min relay fee as tx fee floor: 1000 sat/kvB (1.0 sat/vB)
|
|
2020-04-07 20:46:50,452 [INFO] Using a fee of : 0.00000200 BTC (200 sat).
|
|
2020-04-07 20:46:50,454 [INFO] Got signed transaction:
|
|
|
|
2020-04-07 20:46:50,455 [INFO] {'ins': [{'outpoint': {'hash': '61d69b4e7abe0ef8a5a9cbabb05463259c3b497a142130a56f81a9259f048cb0',
|
|
'index': 0},
|
|
'script': '160014295beb4eba9b35896683d5b5ff455ee2c646054c',
|
|
'sequence': 4294967294,
|
|
'txinwitness': ['3045022100939de908e30015c6b22d2c0f25153e395268466ce44eeeb4ec03a8920440e87b0220155d1c43dedb3fc2654205541bb2821dd5211180e2d7f93d67301470652830d401',
|
|
'03ec0f8b267f99ff5259195ce63813d58f38ffbaada894ce06af0c0303c74bbf82']}],
|
|
'locktime': 1361,
|
|
'outs': [{'script': '6a147631c805d8ad9239677b8d7530353fda3fec07ca',
|
|
'value': 11999800}],
|
|
'version': 2}
|
|
2020-04-07 20:46:50,455 [INFO] In serialized form (for copy-paste):
|
|
2020-04-07 20:46:50,455 [INFO] 02000000000101b08c049f25a9816fa53021147a493b9c256354b0abcba9a5f80ebe7a4e9bd6610000000017160014295beb4eba9b35896683d5b5ff455ee2c646054cfeffffff01381ab70000000000166a147631c805d8ad9239677b8d7530353fda3fec07ca02483045022100939de908e30015c6b22d2c0f25153e395268466ce44eeeb4ec03a8920440e87b0220155d1c43dedb3fc2654205541bb2821dd5211180e2d7f93d67301470652830d4012103ec0f8b267f99ff5259195ce63813d58f38ffbaada894ce06af0c0303c74bbf8251050000
|
|
2020-04-07 20:46:50,456 [INFO] Sends: 0.11999800 BTC (11999800 sat) to destination: BURNER OUTPUT embedding pubkey at m/49'/1'/0'/3/0
|
|
|
|
WARNING: This transaction if broadcasted will PERMANENTLY DESTROY your bitcoins
|
|
|
|
Would you like to push to the network? (y/n):y
|
|
2020-04-07 20:47:52,047 [DEBUG] rpc: sendrawtransaction ['02000000000101b08c049f25a9816fa53021147a493b9c256354b0abcba9a5f80ebe7a4e9bd6610000000017160014295beb4eba9b35896683d5b5ff455ee2c646054cfeffffff01381ab70000000000166a147631c805d8ad9239677b8d7530353fda3fec07ca02483045022100939de908e30015c6b22d2c0f25153e395268466ce44eeeb4ec03a8920440e87b0220155d1c43dedb3fc2654205541bb2821dd5211180e2d7f93d67301470652830d4012103ec0f8b267f99ff5259195ce63813d58f38ffbaada894ce06af0c0303c74bbf8251050000']
|
|
2020-04-07 20:47:52,049 [WARNING] Connection had broken pipe, attempting reconnect.
|
|
2020-04-07 20:47:52,440 [INFO] Transaction sent: 656bb4538f14f2cc874043915907b6c9c46a807ef9818bde771d07630d54b0f7
|
|
done
|
|
|
|
Embedded in the `OP_RETURN` output is the hash of a pubkey from the wallet.
|
|
|
|
Now `OP_RETURN` outputs are not addresses, and because of technical reasons the
|
|
first time they are synchronized the flag `--recoversync` must be used. When
|
|
this is done the burn output will appear in the `wallet-tool.py` display.
|
|
`--recoversync` only needs to be used once, and after that the burner output is
|
|
saved in the `wallet.jmdat` file which can be accesses by all future
|
|
synchronizations.
|
|
|
|
$ python3 wallet-tool.py --datadir=. --recoversync testfidelity2.jmdat
|
|
Enter wallet decryption passphrase:
|
|
2020-04-07 23:09:54,644 [INFO] Found a burner transaction txid=656bb4538f14f2cc874043915907b6c9c46a807ef9818bde771d07630d54b0f7 path = m/49'/1'/0'/3/0
|
|
2020-04-07 23:09:54,769 [WARNING] Merkle branch not available, use wallet-tool `addtxoutproof`
|
|
2020-04-07 23:09:55,420 [INFO] Found a burner transaction txid=656bb4538f14f2cc874043915907b6c9c46a807ef9818bde771d07630d54b0f7 path = m/49'/1'/0'/3/0
|
|
2020-04-07 23:09:55,422 [WARNING] Merkle branch not available, use wallet-tool `addtxoutproof`
|
|
JM wallet
|
|
mixdepth 0 fbonds-mpk-tpubDDCXgSpdxuVbXgzRYBggFeMRNeV9eH24jJuQNunyqwYtDFiB7ZS63LhXwHkf7o9ZcZW4qUz7uvD6yk4BkkF3bBPmJRPv7RBTEA5hHwEdV2f
|
|
external addresses m/49'/1'/0'/0 tpubDEJGorVywRb6LoLQbaqWZh2gYwpdZqViCNZ2ejB5kpBuUp16LHpK6ESFaJLixidtbmmjcDwVZ4QjnAbKmypfuGaEk3ifgonPv4vsugqgp9G
|
|
m/49'/1'/0'/0/2 2MviB2FfLKZjFb3W2dJ8kXcQBj3jqMJg7TL 0.00000000 new
|
|
m/49'/1'/0'/0/3 2MtsAQhE2u9VGV3aZ7XM4PzwWGHXr4PAhqP 0.00000000 new
|
|
m/49'/1'/0'/0/4 2N3iXNjS4vkTXzy5Jidnovc6FJeNQJx5Fnt 0.00000000 new
|
|
m/49'/1'/0'/0/5 2MtT4XAjwQQ7PBbrTxv7qcQMMmz4Rs5XrE3 0.00000000 new
|
|
m/49'/1'/0'/0/6 2NEuG23BQESuZTqSDtab9zYsd1Jb4KfMULB 0.00000000 new
|
|
m/49'/1'/0'/0/7 2N6NGJRX6KYQWtYWK8iHFuJNpZRs8NbUAC9 0.00000000 new
|
|
Balance: 0.00000000
|
|
internal addresses m/49'/1'/0'/1
|
|
Balance: 0.00000000
|
|
internal addresses m/49'/1'/0'/2 tpubDEJGorVywRb6T34X7ZAEz9hQYn6CCEhrcFa8kA2mqNau2DvoggZP2QTtXRe8t9NSfMkx3ye8QDzqCE9gEqso6fw5ALk5xycWLFwTRLSqSUV
|
|
Balance: 0.00000000
|
|
internal addresses m/49'/1'/0'/3 tpubDEJGorVywRb6V5em9Q7LFJ9eLEAEZmZxUdDmkknrKNUs7vKcCWPKwP8YPjuxFCCXk2F1wJnubNbmgbtWed5yiE3D1qxzLonVuXT6QEZPaof
|
|
m/49'/1'/0'/3/0 BURN-7631c805d8ad9239677b8d7530353fda3fec07ca 0.11999800 656bb4538f14f2cc874043915907b6c9c46a807ef9818bde771d07630d54b0f7 [NO MERKLE PROOF]
|
|
Balance: 0.11999800
|
|
Balance for mixdepth 0: 0.11999800
|
|
|
|
#### Adding the merkle proof of a burn transaction if missing
|
|
|
|
In order to prove a burn output exists, a merkle proof is needed. If the Core
|
|
node is pruned and the block deleted then JoinMarket will not be able to obtain
|
|
the merkle proof (as in the above example). In this case the proof can be
|
|
added separately.
|
|
|
|
Any other unpruned Core node can trustlessly obtain the proof and give it to
|
|
the user with the RPC call `gettxoutproof`.
|
|
|
|
First obtain the merkle proof:
|
|
|
|
$ bitcoin-cli gettxoutproof "[\"656bb4538f14f2cc874043915907b6c9c46a807ef9818bde771d07630d54b0f7\"]" 4cce28f4eb1ea1762ec4ceb90529b3ab28c0423ac630c6292319e2b2712daada
|
|
0000002056e4050f54084a1d6e6944b209cce76ebe2da4b37f3aa47ab6c612831d3220471015e80d3050cf0ee05b216036030fe3d4906221196943a30e828741ad4cfaeb05d98c5effff7f20010000000200000002a5910e5cf4e6cb6d55e1e2ca979987772a482e8a8f30b7a6cab8c5671f5c161df7b0540d63071d77de8b81f97e806ac4c9b6075991434087ccf2148f53b46b650105
|
|
|
|
Then add it to the JoinMarket wallet:
|
|
|
|
$ python3 wallet-tool.py -H "m/49'/1'/0'/3/0" testfidelity2.jmdat addtxoutproof 0000002056e4050f54084a1d6e6944b209cce76ebe2da4b37f3aa47ab6c612831d3220471015e80d3050cf0ee05b216036030fe3d4906221196943a30e828741ad4cfaeb05d98c5effff7f20010000000200000002a5910e5cf4e6cb6d55e1e2ca979987772a482e8a8f30b7a6cab8c5671f5c161df7b0540d63071d77de8b81f97e806ac4c9b6075991434087ccf2148f53b46b650105
|
|
Enter wallet decryption passphrase:
|
|
Done
|
|
|
|
The `-H` flag must point to the path containing the burn output.
|
|
|
|
Then synchronizing the wallet won't output the no-merkle-proof warning.
|
|
|