by /u/awemany
The problem of ensuring good security for unconfirmed transactions in Bitcoin is repeatedly discussed in the community. Right now these so-called 0-conf transactions are usually expected to be of low risk in the case of small amounts and face-to-face interaction of merchant and customer.
These face-to-face interactions usually mean that there exist extra-blockchain means of enforcing good manners and discouraging theft (merchant and customer knowing each other, justice system, ...). However, there is no reason to refrain from trying to make this better through technical means.
In principle, transactions that are not yet included in blocks can be replaced by a loose duo of a scammer and a miner willing to help the scammer out, which creates a certain risk for a merchant to accept an unconfirmed Bitcoin transaction.
Apart from preconsensus approaches discussed elsewhere, which will cut down the time window in which a scammer might be successfully double-spending, there is also the option to use payment channels to have secure and fast transactions.
However, this necessitates set up of a payment channel before the transaction takes place, which creates a burden for the customer as well as the merchant. This is the approach taken by the Core variant (BTC) of Bitcoin with their Lightning Network implementation.
A third alternative, proposed here rather for the Cash variant (BCH) of Bitcoin (henceforth simply called Bitcoin) is to use the usual zero-confirmation payment approach, but add a special feature to the transaction that will act as a forfeit, should the scammer attempt a double spend of the money that he sent to the merchant.
In about two months from now, the OP_CHECKDATASIG
and
OP_CHECKDATASIGVERIFY
opcodes are planned to activate for
Bitcoin. Using these opcodes, it is possible to implement such a
forfeit in an automated way. This scheme is hereby named Zero
Confirmation Forfeits, or ZCF for short.
There is an old idea by Peter Todd for a merchant to go forward with a scorched earth policy in case the customer turns out to be a scammer and double-spends.
The idea is described (and criticized) in an older post here on Medium by Mike Hearn here: https://medium.com/@octskyward/replace-by-fee-43edd9a1dd6d.
Then, there is a paper on a scheme that is overall quite close to the one described here: https://eprint.iacr.org/2017/394.pdf
In this paper, the authors describe a way to use specially prepared outputs with specially prepared signatures so that double-spending a transaction will reveal the private key.
In contrast, the scheme that is discussed herein, using the to-be-activated
CHECKDATASIG/-VERIFY
opcodes can also be implemented in a backwards-compatible manner and does
not need the creation of any special outputs before paying a
merchant, unlike the scheme by Solà et al.
All that is needed is upgraded software and customers and merchants can use this scheme right away, without further preparation. This seems highly desirable from a user interface perspective.
This post is merely exploring a proof-of-concept of this scheme. Much work is necessary to make this a real world feature of Bitcoin!
OP_CHECKDATASIG
and OP_CHECKDATASIGVERIFY
, which are tweaked variants
of Andrew Stone's OP_DATASIGVERIFY
opcode, allow to check the validity
of a Bitcoin ECDSA signature in the Bitcoin Script Forth-like
predicate language. OP_CHECKDATASIG
will return true
(1) on
the stack when the triple
[signature] [message] [public key]
turns out to be validly signed data resp. false
(0) for an mismatching signature.
The [message]
part is hashed once
with SHA256
before it is used for checking the signature, a fact which
will become important later in this document. Similarly,
OP_CHECKDATASIGVERIFY
works like OP_CHECKDATASIG
, but will not leave a
result on the stack but rather abort the script as failing, should the
signature turn out not to be valid. A very similar (or even functionally identical) opcode reportedly exists in Blockstream's Elements project as well.
The key insight for this scheme is that double-spending a transaction means double-spending one of its inputs. And double-spending one of its inputs means creating two distinct signatures that are valid for the same public key.
A merchant who requires a zero-confirmation transaction with forfeit (a ZCF transaction) will therefore require from the customer a transaction that has the following structure:
- Inputs:
[P2PKH inputs 1] ... [P2PKH input I]
- Outputs:
[any-type-output 1] ... [any-type-output O] [Forfeit Output]
With the [Forfeit Output]
being the key requirement, though it is also
important that all of the inputs are of the P2PKH type and also from
distinct addresses (otherwise, the customer will lose his
forfeit by default). Only then should a transaction deemed to be of
the Zero Conf Forfeit (ZCF) type.
The forfeit output is a P2SH
output that pays to a specially prepared
forfeit script. This forfeit script will allow to spend the output
using either a scriptSig
that contains just
[signature] [public key] [P2SH script]
or by supplying two distinct messages and signatures for the same public key (the same for the two messages, not the same as above), like this:
[signature1] [message1] [signature2] [message2] [public key] [P2SH script]
The first one is the regular spending case. In this case, the well-behaved customer simply spends his forfeit output like any other P2PKH output and everyone is happy.
In the second case, a miner has seen an attempted double-spend by the
customer and uses the signed data from the double-spending as well as
the regular (paying to the merchant) transaction to spend the forfeit
output to himself. Important to note here is that CHECKDATASIG/-VERIFY
allows to check the signatures of Bitcoin transactions.
Assume that
08454094ee44d4fcb7f92c90d57a10d57ad4dc4d7ccafe08a582fff42b0e08ba:0
is an output that has received 9999.9
testBCH to address
bchreg:qrcj0e448csqtyc8rp5p6fzluk3tytetnu6eyusazv
, like this:
$ ./bitcoin-cli -regtest decoderawtransaction 0200000001c093ebf9c7a22bafbc831b1dcbc075657c82636459c9cd1339926fe6a51959d8000000006b483045022100c7b546f4c2c3bf57f756fc175416a496abda199839ab6588b3eae8bff3f6d0d8022048ba06d2258e4997619ac7644347fe0e1faa78ea8500783e8f37a1633fc4721a412103cdb375ff72e4e42898d80193c4026a91d8acea44a42ddf1c30b72d759e7d40c1feffffff0280790cd4e80000001976a914f127e6b53e2005930718681d245fe5a2b22f2b9f88acd8849800000000001976a914f288e5578c011f98eb4c759e0b0ea9169c1d335e88ac93010000
{
"txid": "08454094ee44d4fcb7f92c90d57a10d57ad4dc4d7ccafe08a582fff42b0e08ba",
"hash": "08454094ee44d4fcb7f92c90d57a10d57ad4dc4d7ccafe08a582fff42b0e08ba",
"size": 226,
"version": 2,
"locktime": 403,
"vin": [
{
"txid": "d85919a5e66f923913cdc9596463827c6575c0cb1d1b83bcaf2ba2c7f9eb93c0",
"vout": 0,
"scriptSig": {
"asm": "3045022100c7b546f4c2c3bf57f756fc175416a496abda199839ab6588b3eae8bff3f6d0d8022048ba06d2258e4997619ac7644347fe0e1faa78ea8500783e8f37a1633fc4721a[ALL|FORKID] 03cdb375ff72e4e42898d80193c4026a91d8acea44a42ddf1c30b72d759e7d40c1",
"hex": "483045022100c7b546f4c2c3bf57f756fc175416a496abda199839ab6588b3eae8bff3f6d0d8022048ba06d2258e4997619ac7644347fe0e1faa78ea8500783e8f37a1633fc4721a412103cdb375ff72e4e42898d80193c4026a91d8acea44a42ddf1c30b72d759e7d40c1"
},
"sequence": 4294967294
}
],
"vout": [
{
"value": 9999.90000000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 f127e6b53e2005930718681d245fe5a2b22f2b9f OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914f127e6b53e2005930718681d245fe5a2b22f2b9f88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"bchreg:qrcj0e448csqtyc8rp5p6fzluk3tytetnu6eyusazv"
]
}
},
{
"value": 0.09995480,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 f288e5578c011f98eb4c759e0b0ea9169c1d335e OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914f288e5578c011f98eb4c759e0b0ea9169c1d335e88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"bchreg:qreg3e2h3sq3lx8tf36euzcw4ytfc8fntc3a3jpsej"
]
}
}
]
}
The customer now creates the following ZCF-enabled transaction to pay
the merchant 4400.0 testBCH at address
bchreg:qp7a5v7t3ejacvznnpf8n6w5k3z9jtjanug7u447fj
and put up a
forfeit of 5599.8 testBCH, that he can spend forward (should he not
double-spend) from his address
bchreg:qz938xjjwnxgtcknd48e0y32zkh96lmg4utd5jc66s
:
$ ./bitcoin-cli -regtest decoderawtransaction 0100000001ba080e2bf4ff82a508feca7c4ddcd47ad5107ad5902cf9b7fcd444ee94404508000000006a4730440220665817cdf25beb8505fee4ecc8239e63d973183f5741d9bee68f883df1c8c04402204e5a08daee4a65c68eaf90e7f60ed0b436de16f49b5aca48724c70d9f32a41cb412103cdb375ff72e4e42898d80193c4026a91d8acea44a42ddf1c30b72d759e7d40c1000000000200300b72660000001976a9147dda33cb8e65dc3053985279e9d4b444592e5d9f88ac00b368618200000017a914fcc909008e148ac6dc5258d8884fb167da4904c48700000000
{
"txid": "b25d2fff5b0e3f106b6fa31d7ed6a7a1da72f923128316352397aae0da1eec79",
"hash": "b25d2fff5b0e3f106b6fa31d7ed6a7a1da72f923128316352397aae0da1eec79",
"size": 223,
"version": 1,
"locktime": 0,
"vin": [
{
"txid": "08454094ee44d4fcb7f92c90d57a10d57ad4dc4d7ccafe08a582fff42b0e08ba",
"vout": 0,
"scriptSig": {
"asm": "30440220665817cdf25beb8505fee4ecc8239e63d973183f5741d9bee68f883df1c8c04402204e5a08daee4a65c68eaf90e7f60ed0b436de16f49b5aca48724c70d9f32a41cb[ALL|FORKID] 03cdb375ff72e4e42898d80193c4026a91d8acea44a42ddf1c30b72d759e7d40c1",
"hex": "4730440220665817cdf25beb8505fee4ecc8239e63d973183f5741d9bee68f883df1c8c04402204e5a08daee4a65c68eaf90e7f60ed0b436de16f49b5aca48724c70d9f32a41cb412103cdb375ff72e4e42898d80193c4026a91d8acea44a42ddf1c30b72d759e7d40c1"
},
"sequence": 0
}
],
"vout": [
{
"value": 4400.00000000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 7dda33cb8e65dc3053985279e9d4b444592e5d9f OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9147dda33cb8e65dc3053985279e9d4b444592e5d9f88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"bchreg:qp7a5v7t3ejacvznnpf8n6w5k3z9jtjanug7u447fj"
]
}
},
{
"value": 5599.80000000,
"n": 1,
"scriptPubKey": {
"asm": "OP_HASH160 fcc909008e148ac6dc5258d8884fb167da4904c4 OP_EQUAL",
"hex": "a914fcc909008e148ac6dc5258d8884fb167da4904c487",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"bchreg:pr7vjzgq3c2g43ku2fvd3zz0k9na5jgycslg3ae66v"
]
}
}
]
}
The first output is the regular payment to the merchant. The second
one is the P2SH
forfeit output. The script that creates the above P2SH
output is:
76a9148b139a5274cc85e2d36d4f97922a15ae5d7f68af8763ac6776a914f127e6b53e2005930718681d245fe5a2b22f2b9f8763785479879169766bbb6cba676a6868
,
which decodes to:
OP_DUP OP_HASH160 8b139a5274cc85e2d36d4f97922a15ae5d7f68af OP_EQUAL
OP_IF
OP_CHECKSIG
OP_ELSE
OP_DUP OP_HASH160 f127e6b53e2005930718681d245fe5a2b22f2b9f OP_EQUAL
OP_IF
OP_OVER 4 OP_PICK OP_EQUAL OP_NOT OP_VERIFY
OP_DUP OP_TOALTSTACK OP_CHECKDATASIGVERIFY
OP_FROMALTSTACK OP_CHECKDATASIG
OP_ELSE
OP_RETURN
OP_ENDIF
OP_ENDIF
The above idea is implemented here with a couple of nested OP_IF
and
OP_ELSE
statements. Let's go into it in detail:
OP_DUP OP_HASH160 8b139a5274cc85e2d36d4f97922a15ae5d7f68af OP_EQUAL
OP_IF
OP_CHECKSIG
This part looks superficially similar to the scriptPubKey
of a P2PKH
output and indeed it is. Given [sig] [public key]
on the stack, this will hash
the public key, compare it to the given hash / address, check for equality,
and if it is equal, do a regular CHECKSIG
operation. Note that the 1
that is put
on the stack by the OP_EQUAL
will be consumed by the OP_IF
. A successful OP_CHECKSIG
will then lead to a succesful script execution with a 1
on the stack from this signature
checking. This is the code path that allows the customer to regularly spend his forfeit
output forward, in case he decides to not double-spend any of the inputs.
Next, the else path that starts with this:
OP_DUP OP_HASH160 f127e6b53e2005930718681d245fe5a2b22f2b9f OP_EQUAL
OP_IF
Again, this looks superficially similar to a standard output. Here, the public key of a stack
that contains [signature1] [message1] [signature2] [message2] [public-key]
is checked
not for being a valid key for spending the output, but is rather checked to be one of the input
public keys. This is to test for double spending any input. Again the OP_EQUAL
and OP_IF
combination
will leave the stack as it was upon entry into the script.
As noted above, the signatures and messages are expected to be extracts of Bitcoin transactions, more specifically
the transaction to the merchant with the forfeit output itself, plus the attempted double-spend by the customer
turned scammer.
So, to continue in this code path:
OP_OVER 4 OP_PICK OP_EQUAL OP_NOT OP_VERIFY
This checks for the messages being not equal and will fail the script otherwise. First, the message2
is picked and
put onto the stack once more with OP_OVER
, and then 4 OP_PICK
picks the message1
. They are compared for inequality
then with OP_EQUAL OP_NOT OP_VERIFY
, with terminal failure if they are equal.
Then,
OP_DUP OP_TOALTSTACK OP_CHECKDATASIGVERIFY
OP_FROMALTSTACK OP_CHECKDATASIG
Checks the two message, pubkey, signature combinations using CHECKDATASIG
resp. CHECKDATASIGVERIFY
. The pubkey is needed
for both checks and is saved for convenience onto the altstack with OP_DUP OP_TOALTSTACK
. The triple (signature2, message2, public key)
is first checked with OP_CHECKDATASIGVERIFY
and then the triple (signature1, message1, public key)
is checked with
OP_FROMALTSTACK OP_CHECKDATASIG
, leaving the final 1
for success on the stack.
What follows is
OP_ELSE
OP_RETURN
OP_ENDIF
OP_ENDIF
which is the else path ending in an invalidating OP_RETURN
in case other data is supplied to the script. In the following, an example of each valid code path and spending situation is now presented.
In the first case of a regular spend, the
supplied pubkey is hashed to yield address 8b139..
(qz938xjj..
)
and a regular OP_CHECKSIG
is executed. Such a regular spending
transaction could for example be the following, which just spends the
above output forward to the same address:
$ ./bitcoin-cli -regtest decoderawtransaction 010000000179ec1edae0aa97233516831223f972daa1a7d67e1da36f6b103f0e5bff2f5db201000000af4830450221009800712a9042fc2bcf7cce2be6d907f064ddf61b55183d4988d9cd1128fb422a0220070cf7db4e1cea03e3cf0d902bfff44071f93e7a1446b8724fb7845c1d1d6e0641210320db2c52e5d23f2730770ca136c717359c73c1d1b9a4bf288bf3606bf116353f4376a9148b139a5274cc85e2d36d4f97922a15ae5d7f68af8763ac6776a914f127e6b53e2005930718681d245fe5a2b22f2b9f8763785479879169766bbb6cba676a6868000000000118af6861820000001976a9148b139a5274cc85e2d36d4f97922a15ae5d7f68af88ac00000000
{
"txid": "7f6c4b6e21d80b6e0ce36cefe85c010603332d9d981da7231a667fed2b9053f7",
"hash": "7f6c4b6e21d80b6e0ce36cefe85c010603332d9d981da7231a667fed2b9053f7",
"size": 260,
"version": 1,
"locktime": 0,
"vin": [
{
"txid": "b25d2fff5b0e3f106b6fa31d7ed6a7a1da72f923128316352397aae0da1eec79",
"vout": 1,
"scriptSig": {
"asm": "30450221009800712a9042fc2bcf7cce2be6d907f064ddf61b55183d4988d9cd1128fb422a0220070cf7db4e1cea03e3cf0d902bfff44071f93e7a1446b8724fb7845c1d1d6e06[ALL|FORKID] 0320db2c52e5d23f2730770ca136c717359c73c1d1b9a4bf288bf3606bf116353f 76a9148b139a5274cc85e2d36d4f97922a15ae5d7f68af8763ac6776a914f127e6b53e2005930718681d245fe5a2b22f2b9f8763785479879169766bbb6cba676a6868",
"hex": "4830450221009800712a9042fc2bcf7cce2be6d907f064ddf61b55183d4988d9cd1128fb422a0220070cf7db4e1cea03e3cf0d902bfff44071f93e7a1446b8724fb7845c1d1d6e0641210320db2c52e5d23f2730770ca136c717359c73c1d1b9a4bf288bf3606bf116353f4376a9148b139a5274cc85e2d36d4f97922a15ae5d7f68af8763ac6776a914f127e6b53e2005930718681d245fe5a2b22f2b9f8763785479879169766bbb6cba676a6868"
},
"sequence": 0
}
],
"vout": [
{
"value": 5599.79999000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 8b139a5274cc85e2d36d4f97922a15ae5d7f68af OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9148b139a5274cc85e2d36d4f97922a15ae5d7f68af88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"bchreg:qz938xjjwnxgtcknd48e0y32zkh96lmg4utd5jc66s"
]
}
}
]
}}
Note the scriptSig
that pushes a signature and pubkey just like for a
regular P2PKH
output, plus the P2SH
script itself, as needed for P2SH
outputs.
Now, if the customer is a scammer and double-spent the transaction, two different signature and message combinations will exist for the public pair. Spending the forfeit might then look like this:
$ ./bitcoin-cli -regtest decoderawtransaction 010000000179ec1edae0aa97233516831223f972daa1a7d67e1da36f6b103f0e5bff2f5db201000000fd3701473045022100cf7e027d3423845c8db9ea81654c739bb009454728cee307cda2963f672c7cc2022012a2ed81a9544ce8eaf47cfbb466a6267684127fd06cc423c4e2a3c702173d212093f66ecca97e91ab69cf8e62838e92992d0a25a4432d6e75da9ba7b90a82d6bf4630440220665817cdf25beb8505fee4ecc8239e63d973183f5741d9bee68f883df1c8c04402204e5a08daee4a65c68eaf90e7f60ed0b436de16f49b5aca48724c70d9f32a41cb20a51b7e2846c3dbbe54fd830461db15f3d18f63d1f596baafb2a8c8b4ef90e6582103cdb375ff72e4e42898d80193c4026a91d8acea44a42ddf1c30b72d759e7d40c14376a9148b139a5274cc85e2d36d4f97922a15ae5d7f68af8763ac6776a914f127e6b53e2005930718681d245fe5a2b22f2b9f8763785479879169766bbb6cba676a6868000000000100b36861820000001976a914b0db3d9021a1066ed5be4c2954162a6f4e757c8c88ac00000000
{
"txid": "4d351c6b0eb615bdd8b826aa2af4bf9f3f1b8d2f7aa95cd2f4c0c19ecd9cec76",
"hash": "4d351c6b0eb615bdd8b826aa2af4bf9f3f1b8d2f7aa95cd2f4c0c19ecd9cec76",
"size": 398,
"version": 1,
"locktime": 0,
"vin": [
{
"txid": "b25d2fff5b0e3f106b6fa31d7ed6a7a1da72f923128316352397aae0da1eec79",
"vout": 1,
"scriptSig": {
"asm": "3045022100cf7e027d3423845c8db9ea81654c739bb009454728cee307cda2963f672c7cc2022012a2ed81a9544ce8eaf47cfbb466a6267684127fd06cc423c4e2a3c702173d21 93f66ecca97e91ab69cf8e62838e92992d0a25a4432d6e75da9ba7b90a82d6bf 30440220665817cdf25beb8505fee4ecc8239e63d973183f5741d9bee68f883df1c8c04402204e5a08daee4a65c68eaf90e7f60ed0b436de16f49b5aca48724c70d9f32a41cb a51b7e2846c3dbbe54fd830461db15f3d18f63d1f596baafb2a8c8b4ef90e658 03cdb375ff72e4e42898d80193c4026a91d8acea44a42ddf1c30b72d759e7d40c1 76a9148b139a5274cc85e2d36d4f97922a15ae5d7f68af8763ac6776a914f127e6b53e2005930718681d245fe5a2b22f2b9f8763785479879169766bbb6cba676a6868",
"hex": "473045022100cf7e027d3423845c8db9ea81654c739bb009454728cee307cda2963f672c7cc2022012a2ed81a9544ce8eaf47cfbb466a6267684127fd06cc423c4e2a3c702173d212093f66ecca97e91ab69cf8e62838e92992d0a25a4432d6e75da9ba7b90a82d6bf4630440220665817cdf25beb8505fee4ecc8239e63d973183f5741d9bee68f883df1c8c04402204e5a08daee4a65c68eaf90e7f60ed0b436de16f49b5aca48724c70d9f32a41cb20a51b7e2846c3dbbe54fd830461db15f3d18f63d1f596baafb2a8c8b4ef90e6582103cdb375ff72e4e42898d80193c4026a91d8acea44a42ddf1c30b72d759e7d40c14376a9148b139a5274cc85e2d36d4f97922a15ae5d7f68af8763ac6776a914f127e6b53e2005930718681d245fe5a2b22f2b9f8763785479879169766bbb6cba676a6868"
},
"sequence": 0
}
],
"vout": [
{
"value": 5599.80000000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 b0db3d9021a1066ed5be4c2954162a6f4e757c8c OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914b0db3d9021a1066ed5be4c2954162a6f4e757c8c88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"bchreg:qzcdk0vsyxssvmk4hexzj4qk9fh5uatu3s29fz5p5t"
]
}
}
]
}
The scriptSig
here is a lot more verbose, containing the two
signatures, the two messages (hashes) as well as the public key (that hashes to f127...
) and
finally the P2SH
script.
In this example, the miner would spend the forfeit to a miner-owned address. This could be simplified, of course, to be a transaction without any outputs, therefore spending everything as fees to himself. For testing this, it was a lot simpler to make this a regular-looking transaction, however.
Any other input should end up in the OP_RETURN
and thus fail to
spend the output.
To be noted here is that CHECKDATASIG
will hash the input given to it
once. Very luckily, any transaction input of the P2PKH
type is hashed
twice before its signature is checked in bitcoind
(for the
required SIGHASH_FORKID
signature type). This allows to supply the
single hashing intermediate result from the SignatureHash(..)
function in bitcoind
to this script to enable the forfeit logic.
In case of more inputs, the above script would be adapted with more
input public key hashes in an OP_OR
clause or similar.
The whole "implementation" right now consists of a bunch of very
messy, still unpublished ad-hoc scripts based on the primal100
variant of Vitalik' Buterins pybitcointools
(https://github.com/primal100/pybitcointools) plus an abuse of the
functional test suite in the Bitcoin Unlimited software
stack. Furthermore, as Bitcoin Unlimited has not yet been updated to
support the CHECKDATASIG
/-VERIFY
opcodes, the above example has been
created and tested using the BitcoinABC implementation.
For reference, to allow playing with CHECKDATASIG
, it should be started like this:
./bitcoind -regtest -debug -magneticanomalyactivationtime=0 -relaypriority=0
In short, all this needs to be cleaned up, as well as documented, as well as implemented in consumer wallets such as Copay to be of real use. Furthermore, mining software likely needs to be adapted to allow an exemption for double-spending the discussed forfeit outputs described here in. A standard needs to be written - and so forth ...
If this is deemed to be an acceptable way to deal with the 0-conf problem, it might make sense to change the mining code in leading implementations to allow spending forfeits easy as a discouragement of scammers.
It should finally be noted that the nature of this change is one that "in the expected case, it will never be used". Just having this feature around might be enough deterrent for scammers to not try scamming - and using ZCF transactions should deter potential scammers from trying.
However, it is also imaginable that this feature will - if implemented ecosystem-wide - rarely be used, as 0-conf is currently quite usable for low risk anyways. This might end up with a minor Volterra-Lotka-like dynamic with a low amount of scams happening and merchants reacting by requiring forfeits.
I propose that wallets and point-of-sale system display a transaction protected with a sufficient (TBD) forfeit with a green 'F' in their user interfaces.
The above presents a scheme to create forfeit outputs that would
discourage people from double-spending unconfirmed payments to
merchants. It includes an example set of regtest
transactions to
demonstrate the general idea.
The author is happy for any input on this, including bug reports, pointers to related work and similar. Finally, I like to thank Andrew Stone and one anonymous reviewer for having a detailed look at the draft of this post.
I also further like to thank Andrew Stone and imaginary_username
, because AFAIR I developed
this idea when throwing ideas back and forth in a discussion with them on the Bitcoin Unlimited slack.
(Final editing note: I planned to publish this on Medium, but it screwed up the formatting of all the code. So I am leaving it here on github then.)
From the discussion on reddit: One worry that was mentioned by user TorusJKL and others is that there might be collusion between miner and scammer. In this case, one way to address this is to increase the forfeit, assuming the double spend is sent into the network. And if reaches only a particular miner, adding an extra time lock on the forfeit until it can be spend forward (but only in the regular spending case) would seem to further discourage this kind of collusion.
Hey @awemany, thank you for your work on this idea! We figured out some more details and put it all together as a CHIP: https://github.com/bitjson/bch-zce
If you're interested, we'd love to know what you think!