[Lightning-dev] Arbitrary Bitcoin Contracts over LN

ZmnSCPxj ZmnSCPxj at protonmail.com
Thu Aug 2 03:43:23 UTC 2018


Good morning Christian,

> My issue is with the fact that CLTV-branches and nLocktimed spending
> transactions also need to be guarded with a further `OP_CSV` condition,
> since they may leak on-chain, and be immediately valid. This is the
> reason why we introduced the two stage HTLC resolution, with the first
> stage acting as the `OP_CSV` guard, and keeping the second stage clean.
>
> I think therefore the construction of the contract ought to be this:
>
> [/arbitrary/, A && B] -> [signA signB, (revoke) || (CSV && A && B && C)] -> [signA signB witnessCbyA, revoke || A] /* held by A */
> [/arbitrary/, A && B] -> [signA signB, (revoke) || (CSV && A && B && C)] -> [signA signB witnessCbyB, revoke || B] /* held by B */
>
> Namely the CSV belongs in the output script, not the input script (which
> is under the control of the spending party). Notice that I might have
> misgroked your syntax :-) If C now contains a CLTV-branch whose timeout
> expires before we attempt the on-chain mediation, suddenly both branches
> become valid and we have a race.

I believe not.  In the BOLT #3, a received HTLC looks like this:

    ## (revoke) ||
    OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
    OP_IF
        OP_CHECKSIG
    OP_ELSE
        ## B &&
        <remote_htlcpubkey> OP_SWAP
            OP_SIZE 32 OP_EQUAL
        ## C
        OP_IF
            # To local node via HTLC-success transaction.
            OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY
            2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG
        OP_ELSE
            # To remote node after timeout.
            OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
            OP_CHECKSIG
        OP_ENDIF
    OP_ENDIF

The above contains no CSV, and is the output of the second transaction (the one that spends the funding transaction directly).  I annotated the SCRIPT with ## of what I consider each component to be (with A=local, B=remote).  I believe it is equivalent to ((revoke) || B && C), where C is the HTLC (A && (x == H(x))) || (CLTV)), with the requirement of A included within C and that this is "simply" an optimization (in principle, we could have required both local and remote HTLC pubkeys for the HTLC, but that just makes our witnesses unnecessarily larger).

It is instead the HTLC-timeout/HTLC-success transactions (which spends from the above script) that have a CSV:

    OP_IF
        ## (revoke) ||
        # Penalty transaction
        <revocationpubkey>
    OP_ELSE
        ## (CSV && A)
        `to_self_delay`
        OP_CSV
        OP_DROP
        <local_delayedpubkey>
    OP_ENDIF
    OP_CHECKSIG

Which I render as ((revoke) || (CSV && A)).

The need for the CSV here is precisely what you described, but it comes *after* the contract being enforced, not before.

Thus under Poon-Dryja the CSV occurs on a transaction that is dependent on a CLTV, not the other way around, and the CSV does not interfere with the CLTV. (indeed with current LN the CSV never comes into play during routing; if CSV interfered with CLTV here, then it should have been considered in our routing algorithm. instead we need to plan out this CSV-interference when we eventually move to Decker-Osuntokun-Russell eltoo channels.)

The drawback is that the condition in the second transaction becomes complicated, and thus cleverness like the above eliding of A from A && B && C is needed to keep witnesses and script size down.

Sincerely,
AmkG


More information about the Lightning-dev mailing list