← Back to Basis of Lightning Technology
BOLT 3specificationlightningsegwitpaymentskey-managementtransactionsscript

BOLT 3: Bitcoin Transaction and Script Formats

This details the exact format of on-chain transactions, which both sides need to agree on to ensure signatures are valid. This consists of the funding transaction output script, the commitment transactions, and the HTLC transactions.

No reviews
Unknown·Updated Mar 28, 2026·0 reviews·0 attestations·View source
Collections:BOLTs — Merged

Specification

BOLT #3: Bitcoin Transaction and Script Formats

This details the exact format of on-chain transactions, which both sides need to agree on to ensure signatures are valid. This consists of the funding transaction output script, the commitment transactions, and the HTLC transactions.

Table of Contents

Transactions

Transaction Output Ordering

Outputs in transactions are always sorted according to:

  • first according to their value, smallest first (in whole satoshis, note that for HTLC outputs, the millisatoshi part must be ignored)
  • followed by scriptpubkey, comparing the common-length prefix lexicographically as if by memcmp, then selecting the shorter script (if they differ in length),
  • finally, for HTLC outputs, in increasing cltv_expiry order.

Rationale

Two offered HTLCs which have the same amount (rounded from amount_msat) and payment_hash will have identical outputs, even if their cltv_expiry differs. This only matters because the same ordering is used to send htlc_signatures and the HTLC transactions themselves are different, thus the two peers must agree on the canonical ordering for this case.

Use of Segwit

Most transaction outputs used here are pay-to-witness-script-hash<sup>BIP141</sup> (P2WSH) outputs: the Segwit version of P2SH. To spend such outputs, the last item on the witness stack must be the actual script that was used to generate the P2WSH output that is being spent. This last item has been omitted for brevity in the rest of this document.

A <> designates an empty vector as required for compliance with MINIMALIF-standard rule.<sup>MINIMALIF</sup>

Funding Transaction Output

  • The funding output script is a P2WSH to:

2 <pubkey1> <pubkey2> 2 OP_CHECKMULTISIG

  • Where pubkey1 is the lexicographically lesser of the two funding_pubkey in compressed format, and where pubkey2 is the lexicographically greater of the two.

Commitment Transaction

  • version: 2
  • locktime: upper 8 bits are 0x20, lower 24 bits are the lower 24 bits of the obscured commitment number
  • txin count: 1
    • txin[0] outpoint: txid and output_index from funding_created message
    • txin[0] sequence: upper 8 bits are 0x80, lower 24 bits are upper 24 bits of the obscured commitment number
    • txin[0] script bytes: 0
    • txin[0] witness: 0 <signature_for_pubkey1> <signature_for_pubkey2>

The 48-bit commitment number is obscured by XOR with the lower 48 bits of:

SHA256(payment_basepoint from open_channel || payment_basepoint from accept_channel)

This obscures the number of commitments made on the channel in the case of unilateral close, yet still provides a useful index for both nodes (who know the payment_basepoints) to quickly find a revoked commitment transaction.

Commitment Transaction Outputs

To allow an opportunity for penalty transactions, in case of a revoked commitment transaction, all outputs that return funds to the owner of the commitment transaction (a.k.a. the "local node") must be delayed for to_self_delay blocks. For HTLCs this delay is done in a second-stage HTLC transaction (HTLC-success for HTLCs accepted by the local node, HTLC-timeout for HTLCs offered by the local node).

The reason for the separate transaction stage for HTLC outputs is so that HTLCs can timeout or be fulfilled even though they are within the to_self_delay delay. Otherwise, the required minimum timeout on HTLCs is lengthened by this delay, causing longer timeouts for HTLCs traversing the network.

The amounts for each output MUST be rounded down to whole satoshis. If this amount, minus the fees for the HTLC transaction, is less than the dust_limit_satoshis set by the owner of the commitment transaction, the output MUST NOT be produced (thus the funds add to fees).

to_local Output

This output sends funds back to the owner of this commitment transaction and thus must be timelocked using OP_CHECKSEQUENCEVERIFY. It can be claimed, without delay, by the other party if they know the revocation private key. The output is a version-0 P2WSH, with a witness script:

OP_IF
    # Penalty transaction
    <revocationpubkey>
OP_ELSE
    `to_self_delay`
    OP_CHECKSEQUENCEVERIFY
    OP_DROP
    <local_delayedpubkey>
OP_ENDIF
OP_CHECKSIG

The output is spent by an input with nSequence field set to to_self_delay (which can only be valid after that duration has passed) and witness:

<local_delayedsig> <>

If a revoked commitment transaction is published, the other party can spend this output immediately with the following witness:

<revocation_sig> 1

to_remote Output

If option_anchors applies to the commitment transaction, the to_remote output is encumbered by a one block csv lock.

<remotepubkey> OP_CHECKSIGVERIFY 1 OP_CHECKSEQUENCEVERIFY

The output is spent by an input with nSequence field set to 1 and witness:

<remote_sig>

Otherwise, this output is a simple P2WPKH to remotepubkey.

to_local_anchor and to_remote_anchor Output (option_anchors)

This output can be spent by the local and remote nodes respectively to provide incentive to mine the transaction, using child-pays-for-parent. Both anchor outputs are always added, except for the case where there are no htlcs and one of the parties has a commitment output that is below the dust limit. In that case only an anchor is added for the commitment output that does materialize. This typically happens if the initiator closes right after opening (no to_remote output).

<local_funding_pubkey/remote_funding_pubkey> OP_CHECKSIG OP_IFDUP
OP_NOTIF
    OP_16 OP_CHECKSEQUENCEVERIFY
OP_ENDIF

Each party has its own anchor output that locks to their funding key. This is to prevent a malicious peer from attaching child transactions with a low fee density to an anchor and thereby blocking the victim from getting the commit tx confirmed in time. This defense is supported by a change in Bitcoin core 0.19: https://github.com/bitcoin/bitcoin/pull/15681. This is also the reason that every non-anchor output on the commit tx is CSV locked.

To prevent utxo set pollution, any anchor that remains unspent can be spent by anyone after the commitment tx confirms. This is also the reason to lock the anchor outputs to the funding key. Third parties can observe this key and reconstruct the spend script, even if none of the commitment outputs would be spent. This does assume that at some point the fee market goes down to a level where sweeping the anchors is economical.

The amount of the output is fixed at 330 sats, the default dust limit for P2WSH.

Spending of the output requires the following witness:

<local_sig/remote_sig>

After 16 blocks, anyone can sweep the anchor with witness:

<>

Offered HTLC Outputs

This output sends funds to either an HTLC-timeout transaction after the HTLC-timeout or to the remote node using the payment preimage or the revocation key. The output is a P2WSH, with a witness script (no option_anchors):

# To remote node with revocation key
OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
OP_IF
    OP_CHECKSIG
OP_ELSE
    <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
    OP_NOTIF
        # To local node via HTLC-timeout transaction (timelocked).
        OP_DROP 2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG
    OP_ELSE
        # To remote node with preimage.
        OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY
        OP_CHECKSIG
    OP_ENDIF
OP_ENDIF

Or, with option_anchors:

# To remote node with revocation key
OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
OP_IF
    OP_CHECKSIG
OP_ELSE
    <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
    OP_NOTIF
        # To local node via HTLC-timeout transaction (timelocked).
        OP_DROP 2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG
    OP_ELSE
        # To remote node with preimage.
        OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY
        OP_CHECKSIG
    OP_ENDIF
    1 OP_CHECKSEQUENCEVERIFY OP_DROP
OP_ENDIF

The remote node can redeem the HTLC with the witness:

<remotehtlcsig> <payment_preimage>

Note that if option_anchors applies, the nSequence field of the spending input must be 1.

If a revoked commitment transaction is published, the remote node can spend this output immediately with the following witness:

<revocation_sig> <revocationpubkey>

The sending node can use the HTLC-timeout transaction to timeout the HTLC once the HTLC is expired, as shown below. This is the only way that the local node can timeout the HTLC, and this branch requires <remotehtlcsig>, which ensures that the local node cannot prematurely timeout the HTLC since the HTLC-timeout transaction has cltv_expiry as its specified locktime. The local node must also wait to_self_delay before accessing these funds, allowing for the remote node to claim these funds if the transaction has been revoked.

Received HTLC Outputs

This output sends funds to either the remote node after the HTLC-timeout or using the revocation key, or to an HTLC-success transaction with a successful payment preimage. The output is a P2WSH, with a witness script (no option_anchors):

# To remote node with revocation key
OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
OP_IF
    OP_CHECKSIG
OP_ELSE
    <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
    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

Or, with option_anchors:

# To remote node with revocation key
OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
OP_IF
    OP_CHECKSIG
OP_ELSE
    <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
    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
    1 OP_CHECKSEQUENCEVERIFY OP_DROP
OP_ENDIF

To timeout the HTLC, the remote node spends it with the witness:

<remotehtlcsig> <>

Note that if option_anchors applies, the nSequence field of the spending input must be 1.

If a revoked commitment transaction is published, the remote node can spend this output immediately with the following witness:

<revocation_sig> <revocationpubkey>

To redeem the HTLC, the HTLC-success transaction is used as detailed below. This is the only way that the local node can spend the HTLC, since this branch requires <remotehtlcsig>, which ensures that the local node must wait to_self_delay before accessing these funds allowing for the remote node to claim these funds if the transaction has been revoked.

Trimmed Outputs

Each peer specifies a dust_limit_satoshis below which outputs should not be produced; these outputs that are not produced are termed "trimmed". A trimmed output is considered too small to be worth creating: it is instead either added to the commitment transaction fee.

For HTLCs, it needs to be taken into account that the second-stage HTLC transac

[Content truncatedview full spec at source]

Discussion (0 threads)

No discussion yet. Be the first to comment.