Skip to content

Commit c00154f

Browse files
committed
Use miniscript to generate scripts for taproot transactions
This means that we are no longer compatible with the current "simple taproot channels" proposals, which needs to be updated anyway.
1 parent a9a02d9 commit c00154f

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,16 +314,32 @@ object Scripts {
314314
* Specific scripts for taproot channels
315315
*/
316316
object Taproot {
317+
// miniscript: older(16)
317318
val anchorScript: Seq[ScriptElt] = OP_16 :: OP_CHECKSEQUENCEVERIFY :: Nil
318319

319320
val anchorScriptTree = new ScriptTree.Leaf(anchorScript.map(scala2kmp).asJava)
320321

321-
def toRevokeScript(revocationPubkey: PublicKey, localDelayedPaymentPubkey: PublicKey): Seq[ScriptElt] = {
322-
OP_PUSHDATA(localDelayedPaymentPubkey.xOnly) :: OP_DROP :: OP_PUSHDATA(revocationPubkey.xOnly) :: OP_CHECKSIG :: Nil
322+
/**
323+
* sends to a single revocation key
324+
* miniscript: pk(revocation_key))
325+
*
326+
* @param revocationPubkey revocation key
327+
* @return a script that will be used to add a "revocation" leaf to a script tree
328+
*/
329+
def toRevokeScript(revocationPubkey: PublicKey): Seq[ScriptElt] = {
330+
OP_PUSHDATA(revocationPubkey.xOnly) :: OP_CHECKSIG :: Nil
323331
}
324332

333+
/**
334+
* sends to a single key after a delay
335+
* miniscript: and_v(v:pk(delayed_key),older(delay))
336+
*
337+
* @param localDelayedPaymentPubkey delayed payment key
338+
* @param toLocalDelay delay
339+
* @return a script that will be used to add a "to local key" leak to a script tree
340+
*/
325341
def toDelayScript(localDelayedPaymentPubkey: PublicKey, toLocalDelay: CltvExpiryDelta): Seq[ScriptElt] = {
326-
OP_PUSHDATA(localDelayedPaymentPubkey.xOnly) :: OP_CHECKSIG :: Scripts.encodeNumber(toLocalDelay.toInt) :: OP_CHECKSEQUENCEVERIFY :: OP_DROP :: Nil
342+
OP_PUSHDATA(localDelayedPaymentPubkey.xOnly) :: OP_CHECKSIGVERIFY :: Scripts.encodeNumber(toLocalDelay.toInt) :: OP_CHECKSEQUENCEVERIFY :: Nil
327343
}
328344

329345
/**
@@ -336,12 +352,19 @@ object Scripts {
336352
def toLocalScriptTree(revocationPubkey: PublicKey, toSelfDelay: CltvExpiryDelta, localDelayedPaymentPubkey: PublicKey): ScriptTree.Branch = {
337353
new ScriptTree.Branch(
338354
new ScriptTree.Leaf(toDelayScript(localDelayedPaymentPubkey, toSelfDelay).map(scala2kmp).asJava),
339-
new ScriptTree.Leaf(toRevokeScript(revocationPubkey, localDelayedPaymentPubkey).map(scala2kmp).asJava),
355+
new ScriptTree.Leaf(toRevokeScript(revocationPubkey).map(scala2kmp).asJava),
340356
)
341357
}
342358

359+
/**
360+
* sends to a key after a 1 block delay
361+
* miniscript: and_v(v:pk(remote_key),older(1))
362+
*
363+
* @param remotePaymentPubkey remote payment key
364+
* @return a script that will be used to add a "to remote key" leak to a script tree
365+
*/
343366
def toRemoteScript(remotePaymentPubkey: PublicKey): Seq[ScriptElt] = {
344-
OP_PUSHDATA(remotePaymentPubkey.xOnly) :: OP_CHECKSIG :: OP_1 :: OP_CHECKSEQUENCEVERIFY :: OP_DROP :: Nil
367+
OP_PUSHDATA(remotePaymentPubkey.xOnly) :: OP_CHECKSIGVERIFY :: OP_1 :: OP_CHECKSEQUENCEVERIFY :: Nil
345368
}
346369

347370
/**
@@ -353,16 +376,34 @@ object Scripts {
353376
new ScriptTree.Leaf(toRemoteScript(remotePaymentPubkey).map(scala2kmp).asJava)
354377
}
355378

379+
/**
380+
* spending requires signatures from both keys
381+
* miniscript: and_v(v:pk(local_htlc_key),pk(remote_htlc_key))
382+
*
383+
* @param localHtlcPubkey local HTLC key
384+
* @param remoteHtlcPubkey remote HTLC key
385+
* @return a script used to create a "HTLC timeout" leaf in a script tree
386+
*/
356387
def offeredHtlcTimeoutScript(localHtlcPubkey: PublicKey, remoteHtlcPubkey: PublicKey): Seq[ScriptElt] = {
357388
OP_PUSHDATA(localHtlcPubkey.xOnly) :: OP_CHECKSIGVERIFY :: OP_PUSHDATA(remoteHtlcPubkey.xOnly) :: OP_CHECKSIG :: Nil
358389
}
359390

391+
// miniscript: and_v(v:hash160(H),and_v(v:pk(remote_htlc_key),older(1)))
392+
393+
/**
394+
* spending requires a signature and a valid preimage, with a 1-block delay
395+
* miniscript: and_v(v:hash160(H),and_v(v:pk(remote_htlc_key),older(1)))
396+
*
397+
* @param remoteHtlcPubkey remote HTLC key
398+
* @param paymentHash payment hash
399+
* @return a script used to create a "spend offered HTLC" leaf in a script tree
400+
*/
360401
def offeredHtlcSuccessScript(remoteHtlcPubkey: PublicKey, paymentHash: ByteVector32): Seq[ScriptElt] = {
361402
// @formatter:off
362403
OP_SIZE :: encodeNumber(32) :: OP_EQUALVERIFY ::
363404
OP_HASH160 :: OP_PUSHDATA(Crypto.ripemd160(paymentHash)) :: OP_EQUALVERIFY ::
364-
OP_PUSHDATA(remoteHtlcPubkey.xOnly) :: OP_CHECKSIG ::
365-
OP_1 :: OP_CHECKSEQUENCEVERIFY :: OP_DROP :: Nil
405+
OP_PUSHDATA(remoteHtlcPubkey.xOnly) :: OP_CHECKSIGVERIFY ::
406+
OP_1 :: OP_CHECKSEQUENCEVERIFY :: Nil
366407
// @formatter:on
367408
}
368409

@@ -373,6 +414,14 @@ object Scripts {
373414
)
374415
}
375416

417+
/**
418+
* spending requires a signature, an absolute HTLC delay, and a 1-block relative delay
419+
* miniscript: and_v(v:pk(remote_htlc_key),and_v(v:older(1),after(delay)))
420+
*
421+
* @param remoteHtlcPubkey remote HTLC key
422+
* @param lockTime HTLC delay
423+
* @return
424+
*/
376425
def receivedHtlcTimeoutScript(remoteHtlcPubkey: PublicKey, lockTime: CltvExpiry): Seq[ScriptElt] = {
377426
// @formatter:off
378427
OP_PUSHDATA(remoteHtlcPubkey.xOnly) :: OP_CHECKSIG ::
@@ -381,6 +430,14 @@ object Scripts {
381430
// @formatter:on
382431
}
383432

433+
/**
434+
* miniscript: and_v(v:hash160(H),and_v(v:pk(local_key),pk(remote_key)))
435+
*
436+
* @param localHtlcPubkey local HTLC key
437+
* @param remoteHtlcPubkey remote HTLC key
438+
* @param paymentHash payment hash
439+
* @return
440+
*/
384441
def receivedHtlcSuccessScript(localHtlcPubkey: PublicKey, remoteHtlcPubkey: PublicKey, paymentHash: ByteVector32): Seq[ScriptElt] = {
385442
// @formatter:off
386443
OP_SIZE :: encodeNumber(32) :: OP_EQUALVERIFY ::

eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,11 +1150,6 @@ object Transactions {
11501150
}
11511151

11521152
def makeMainPenaltyTx(commitTx: Transaction, localDustLimit: Satoshi, remoteRevocationPubkey: PublicKey, localFinalScriptPubKey: ByteVector, toRemoteDelay: CltvExpiryDelta, remoteDelayedPaymentPubkey: PublicKey, feeratePerKw: FeeratePerKw, commitmentFormat: CommitmentFormat): Either[TxGenerationSkipped, MainPenaltyTx] = {
1153-
val redeemScript = if (commitmentFormat.useTaproot) {
1154-
Nil
1155-
} else {
1156-
toLocalDelayed(remoteRevocationPubkey, toRemoteDelay, remoteDelayedPaymentPubkey)
1157-
}
11581153
val pubkeyScript = if (commitmentFormat.useTaproot) {
11591154
val toLocalScriptTree = Scripts.Taproot.toLocalScriptTree(remoteRevocationPubkey, toRemoteDelay, remoteDelayedPaymentPubkey)
11601155
pay2tr(NUMS_POINT.xOnly, Some(toLocalScriptTree))

eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ class TransactionsSpec extends AnyFunSuite with Logging {
754754
// to-local output script tree, with 2 leaves
755755
val toLocalScriptTree = new ScriptTree.Branch(
756756
new ScriptTree.Leaf(toDelayScript(localDelayedPaymentPriv.publicKey, toLocalDelay).map(scala2kmp).asJava),
757-
new ScriptTree.Leaf(toRevokeScript(localRevocationPriv.publicKey, localDelayedPaymentPriv.publicKey).map(scala2kmp).asJava),
757+
new ScriptTree.Leaf(toRevokeScript(localRevocationPriv.publicKey).map(scala2kmp).asJava),
758758
)
759759

760760
// to-remote output script tree, with a single leaf

0 commit comments

Comments
 (0)