Script fix and notes reflecting wire protocol change

This commit is contained in:
Joseph Poon 2015-12-29 17:10:00 -08:00
parent 56d31697d1
commit 47801bd927

@ -4,13 +4,14 @@ future implementation!
There are multiple R-value hashes supported in HTLCs in the wire protocol. This There are multiple R-value hashes supported in HTLCs in the wire protocol. This
is to support conditional multiparty payments, e.g. 2-of-3 "escrow", which is is to support conditional multiparty payments, e.g. 2-of-3 "escrow", which is
one of the biggest use cases of bitcoin scripting today. An example use case is one of the biggest use cases of bitcoin scripting today. An example use case is
a 3rd party "escrow" verifies whether a seller should be paid. This design is a 3rd party escrow verifies whether a seller should be paid. This design is
such that the "escrow" is not a normal escrow which holds custody, but such that the escrow is not a traditional custodial escrow, but instead
determines who should get the money in the event of non-cooperation. determines who should get the money in the event of non-cooperation.
In this implementation, we are including *future protocol support* but not In this implementation, we are including *wire protocol support* but not
writing code yet for 2-of-3, it is to be implemented later. Arbitrary N-of-M writing code yet for 2-of-3, it is to be implemented later. Arbitrary N-of-M
can be supported, but let's keep this simple for now! can be supported with M values higher than 3 and lower than max script size,
but let's keep this simple for now!
How it works: Require 2-of-3 R-value preimages (from 3 hashes) in order for the How it works: Require 2-of-3 R-value preimages (from 3 hashes) in order for the
HTLC to be fulfilled. For each hop in the payment, it requires this 2-of-3 HTLC to be fulfilled. For each hop in the payment, it requires this 2-of-3
@ -25,25 +26,25 @@ that the escrow produces (or for that matters any of the 3-parties in the
2-of-3). It's some secret which is revealed to authorize payment. So if the 2-of-3). It's some secret which is revealed to authorize payment. So if the
Escrow wants the payment to go through, they disclose the secret (R-value) to Escrow wants the payment to go through, they disclose the secret (R-value) to
the recipient. If the recipient is unable to produce 2-of-3, after the agreed the recipient. If the recipient is unable to produce 2-of-3, after the agreed
timeout, the sender will be refunded. Sender and receiver can agree to authorize timeout, the sender will be refunded. Sender and receiver can agree to
payment in most cases where there is cooperation, escrow is only contacted if authorize payment in most cases where there is cooperation, escrow is only
there is non-cooperation. contacted if there is non-cooperation.
Supported in the wire protocol for the unit8: Supported in the wire protocol for the unit8 (two 4-bit N-of-M):
1: 1-of-1 17 (00010001): 1-of-1
2: 1-of-2 34 (00100010): 2-of-2
3: 2-of-2 35 (00100011): 2-of-3 [with Recipient being 1 of the two N parties]
4: 1-of-3 51 (00110011): 3-of-3
5: 2-of-3
6: 3-of-3
I think the only ones that really matter are 1-of-1, 2-of-3, and maybe 2-of-2 I think the only ones that really matter are 1-of-1, 2-of-3, and 2-of-2. 1-of-2
and 3-of-3 (in that order of declining importance). and 1-of-3 doesn't make sense if the recipient must consent to receiving funds
anyway (pushing funds w/o consent is tricky due to pay-to-contract-hash) so
that's basically a 1-of-1.
Assume the order in the stack is Sender, Recipient, Escrow. Assume the order in the stack is Sender, Escrow, Recipient.
For PAID 2-of-3 Recipient+Escrow, the HTLC stack is: For PAID 2-of-3 Escrow+Recipient, the HTLC stack is:
<BobSig> <0> <RecipientPreimageR> <EscrowPreimageR> <0> <BobSig> <0> <EscrowPreimageR> <RecipientPreimageR> <0>
If it's REFUND because 2-of-3 has not been redeemed in time: If it's REFUND because 2-of-3 has not been redeemed in time:
<AliceSig> <1> <AliceSig> <1>
@ -53,31 +54,31 @@ supplied data as part of the sigScript/redeemScript stack):
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
//Paid //Paid
OP_IF OP_IF
//Optional... <CSVDelay> OP_CSV <CSVDelay> OP_DROP OP_CSV
//Stack: <BobSig> <0> <EscrowPreimageR> <RecipientPreimageR>
//Recipient must agree to receive funds.
OP_HASH160 <RecipientHash> OP_EQUALVERIFY
//Stack: <BobSig> <0> <EscrowPreimageR>
//Either the Sender or Escrow must consent for payment
OP_HASH160 <EscrowHash> OP_EQUAL OP_HASH160 <EscrowHash> OP_EQUAL
//Stack: <BobSig> <0> <RecipientPreimageR> <OP_1> //Stack: <BobSig> <0> <OP_1>
OP_SWAP OP_SWAP
//Stack: <BobSig> <0> <OP_1> <RecipientPreimageR> //Stack: <BobSig> <OP_1> <0>
OP_HASH160 <RecipientHash> OP_EQUAL
//Stack: <BobSig> <0> <OP_1> <OP_1>
OP_ADD
//Stack: <BobSig> <0> <OP_2>
OP_SWAP
//Stack: <BobSig> <OP_2> <0>
OP_HASH160 <SenderHash> OP_EQUAL OP_HASH160 <SenderHash> OP_EQUAL
//Stack: <BobSig> <OP_2> <OP_0> //Stack: <BobSig> <OP_1> <OP_0>
OP_ADD OP_BOOLOR
//Stack: <BobSig> <OP_2> //Stack: <BobSig> <OP_1>
<2> OP_EQUALVERIFY OP_VERIFY
<BobPubKey> <BobPubKey>
//Stack: <BobSig> <BobPubKey> //Stack: <BobSig> <BobPubKey>
//Refund //Refund
OP_ELSE OP_ELSE
//Optional... <CSVDelay> OP_CSV <CSVDelay> OP_DROP OP_CSV
<HTLCTimeout> OP_CLTV <HTLCTimeout> OP_DROP OP_CLTV
<AlicePubKey> <AlicePubKey>
//Stack: <AliceSig> <AlicePubKey> //Stack: <AliceSig> <AlicePubKey>
OP_ENDIF OP_ENDIF
@ -87,37 +88,34 @@ OP_CHECKSIG
Note: It is possible that Alice and Bob may not be Sender, Recipient, nor Note: It is possible that Alice and Bob may not be Sender, Recipient, nor
Escrow! Escrow!
If we have all 3 R-values, we only include 2 and include a dummy zero on the
third.
The result? We can do 2-of-3 escrow payments which refund to the sender after a The result? We can do 2-of-3 escrow payments which refund to the sender after a
timeout! The Buyer and Seller can agree to redeem and they only need to go to timeout! The Sender and Recipient can agree to redeem and they only need to go
the Escrow if there's a dispute. Each node along the path gets paid or refunded to the Escrow if there's a dispute. All nodes along the path gets paid or
atomically, the same as a single-HTLC payment on Lightning. refunded atomically, the same as a single-HTLC payment on Lightning.
Possible Resolution States:
* Recipient paid: Recipient and Sender provide R-values
* Recipient paid: Recipient and Escrow provide R-values
* Sender refunded via timeout: Sender is refunded if Recipient cannot convince
Escrow or Sender to disclose their R-value before HTLC timeout
* Payment immediately cancelled and Sender gets refunded: Payment sent in the
opposite direction enforced by same R-values (if there is sender & receiver
consent & cooperation to cancel payment)
Sender+Escrow isn't going to want to push funds w/o cooperation of Recipient.
However, it's possible to construct a script that way.
Ta-da! "Smart Contract(TM)" maymay. Ta-da! "Smart Contract(TM)" maymay.
Immediately refundable payments (2-of-3 can immediately cancel a payment) are Escrow-enforced immediately refundable payments (2-of-3 can immediately cancel
also possible but requires another payment in the opposite direction with the a payment) are also possible but requires another payment in the opposite
R-value hashed twice (the R value becomes the H), but that's kind of annoying to direction with the R-value hashed twice (the H becomes the R-value) and funds
write... it's easier to just assume immediate refund can only occur if both encumbered in the opposite direction, but that's kind of annoying to write...
Recipient+Sender agree to cancel the payment immediately (otherwise it will it's easier if immediate refund can only occur when both Recipient+Sender agree
wait until the timeout). to cancel the payment immediately (otherwise it will wait until the timeout).
Also: THE ABOVE SCRIPT IS NOT THE MOST EFFICIENT SCRIPT POSSIBLE FOR THIS USE Escrow is only contacted if the recipient needs to redeem and the sender is
CASE! This is to illustrate a similar conceptual use as current 2-of-3 uncooperative so this is still true to the "lazy escrow service" in Bitcoin
multisig. You want to do <EscrowPreimageR> *OR* <SenderPreimageR> since the multisig.
recipient will always redeem if they can. So the hash code block would be
instead: (2-of-2 is also needed for payment cancellation.)
OP_HASH160 <EscrowHash> OP_EQUAL
//Stack: <BobSig> <0> <RecipientPreimageR> <OP_1>
OP_SWAP
//Stack: <BobSig> <OP_1> <0>
OP_HASH160 <SenderHash> OP_EQUAL
//Stack: <BobSig> <OP_1> <OP_0>
OP_BOOLOR
//Stack: <BobSig> <OP_1>
OP_VERIFY
The tradeoff is that if the escrow screws up, then payment can be forced.
Whereas the original script doesn't have that problem if the receiver does not
misbehave.