ここでは、署名が有効であることを保証するために双方が合意する必要があるオンチェーントランザクションの正確なフォーマットを詳述している。これは、資産トランザクション出力スクリプト、コミットメントトランザクション、HTLC トランザクションで構成されている。
Transaction
Use of Segwit
ここで使われているほとんどのトランザクション出力は pay-to-witness-script-hash (P2WSH) 出力(P2SH の Segwit 版)である。このような出力を支出するために witness スタックでの最後のアイテムは、P2WSH を生成するために使用された実際のスクリプトでなければならない。
資産トランザクション出力スクリプトは P2WSH であり、以下のような構造をしている。(pubkey1
は圧縮形式での 2 つの funding_pubkey
で辞書的に小さい方であり、pubkey2
は大きい方である)
2 <pubkey1> <pubkey2> 2 OP_CHECKMULTISIG
Commitment Transaction
コミットメントトランザクションの構造は以下のようになっている。
- version : 2
- locktime : 上位 8 ビットは 0x20 であり、下位 24 ビットは不明瞭なコミット番号の下位 24 ビットである
- txin count : 1
txin[0]
outpoint :funding_created
メッセージのtxid
とoutput_index
txin[0]
sequence : 上位 8 ビットは 0x80 であり、下位 24 ビットは不明瞭なコミット番号の下位 24 ビットであるtxin[0]
script bytes : 0txin[0]
witness :0 <signature_for_pubkey1> <signature_for_pubkey2>
Commitment Transaction Outputs
ペナルティトランザクションの機会を可能にするために、失効したトランザクションの場合、コミットメントトランザクションの所有者に資産を戻す全ての出力は to_self_delay
ブロックのために遅らせる必要がある。この遅延は、第2段階の HTLCトランザクションで行われる。
各アウトプットの1 sat 未満の金額は切り捨てる。HTLC トランザクションの手数料を引いた料金がコミットメントトランザクションの所有者によって設定された dust_limit_satoshis
よりも小さい場合、出力は生成してはいけない(その資産は手数料に追加する)。
to_local
出力
この出力はこのコミットメントトランザクションの所有者に資産を戻し、OP_CHECKSEQUENCEVERIFY
を用いてタイムロックされる必要がある。もし取り消し可能秘密鍵を知っていれば、相手によって遅延なく獲得される。出力は version-0 P2WSH の witness スクリプトである。
to_remote
出力
option_anchor_outputs
がコミットメントトランザクションに適用する場合、to_remote
出力は csv ロックした1つのブロックによって妨げられる。
提供した HTLC 出力
この出力は、HTLC タイムアウト後の HTLC タイムアウトトランザクション、または支払いプリイメージまたは失効キーを使用してリモートノードのいずれかに資金を送る。出力は、witness スクリプトで P2WSH である。
受け取った HTLC 出力
この出力は、HTLC-タイムアウト後、または失効キーを使用してリモートノードに資金を送るか、または支払いプリイメージが成功した HTLC-成功トランザクションに資金を送る。出力は P2WSH であり、witness スクリプト(option_anchor_outputs
はない)を持つ。
トリミングされた出力
各ピアは生成するべきでない出力の下限値 dust_limit_satoshis
を指定している。これらの出力を "トリミングされた" とする。トリムされた出力は生成するには小さすぎると見なされ、代わりにコミットメントトランザクション手数料に追加される。HTLC の場合、2 段目の HTLC 取引も制限値を下回る可能性があることを考慮する必要がある。
HTLC-timeout and HTLC-success Transactions
これらの HTLC トランザクションほ、HTLC-タイムアウトトランザクションはタイムロックされていることを除いて、ほとんど同一である。これらはペナルティトランザクションによって支出することができる。
- version: 2
- locktime:
0
-> HTLC-success,cltv_expiry
-> HTLC-timeout - txin count: 1
txin[0]
outpoint: コミットメントトランザクションのtxid
と and HTLC トランザクションにマッチする HTLC 出力のoutput_index
txin[0]
sequence:0
(option_anchor_outputs
の場合は1
)txin[0]
script bytes:0
txin[0]
witness stack:0 <remotehtlcsig> <localhtlcsig> <payment_preimage>
-> HTLC-success,0 <remotehtlcsig> <localhtlcsig> <>
-> HTLC-timeout
- txout count:
1
- txout[0] amount: HTLC 量 - 手数料
- txout[0] script: version-0 P2WSH with witness script
option_anchor_outputs
をこのコミットメントトランザクションに適応した場合、SIGHASH_SINGLE|SIGHASH_ANYONECANPAY
が使用される
Closing Transaction
各ノードに2つのバリエーションがあることに注意されたい。
- version: 2
- locktime: 0
- txin count: 1
- txin[0] outpoint:
funding_created
メッセージからのtxid
とoutput_index
- txin[0] sequence:
0xFFFFFFFF
- txin[0] script bytes:
0
- txin[0] witness:
0 <signature_for_pubkey1> <signature_for_pubkey2>
- txin[0] outpoint:
- txout count: 0, 1 or 2
- txout amount: 1つのノードに支払われるための最終残高
- txout script:
shutdown
メッセージでノードのscriptpubkey
に指定されているように
Fees
手数料計算
両者のコミットメントトランザクションや HTLC トランザクションの手数料計算は現在の feerate_per_kw
と予想されるトランザクションの重さをベースとしている。実際と予想の重さはいくつかの理由により異なる。
Fee Payment
基本コミットメントトランザクション手数料と to_local
と to_remote_anchor
出力量は出資量から取り除かれる。手数料は出資者への出力から引かれていることに注意されたい。
ノードは:
- 最終手数料が低すぎる場合:
- チャネル開設を失敗する可能性がある
コミットメントトランザクション構造
この章では、あるピアのコミットメントトランザクションを構築するための アルゴリズムを詳細に説明する。 ピアの dust_limit_satoshis
、現在の feerate_per_kw
、各ピア(to_local
と to_remote
)への金額、およびすべてのコミットされた HTLC など。
- コミットメントトランザクションの入力とロックタイムを初期化する
- どのコミットされた HTLC がトリミングに必要なのか計算する
- 基本コミットメントトランザクション手数料を計算する
- 出資者(
to_local
もしくはto_remote
)からこの基本手数料を引く - 提供した HTLC ごとに、トリミングされていない場合は提供した HTLC 出力を追加する
6.受け取った HTLC ごとに、トリミングされていない場合は受け取った HTLC 出力を追加する to_local
量がdust_limit_satoshis
以上の場合、to_local
出力を追加するto_remote
量がdust_limit_satoshis
以上の場合、to_remote
出力を追加するoption_anchor_outputs
がコミットメントトランザクションに適用される場合:to_local
が存在する、もしくはトリミングされていない HTLC がある場合、to_local_anchor
出力を追加するto_remote
が存在する、もしくはトリミングされていない HTLC がある場合、to_remote_anchor
出力を追加する
- BIP 69+CTLV order に沿ってソートする
Keys
Key Derivation
各コミットメントトランザクションは一意の localpubkey
と remotepubkey
を使用している。HTLC-成功と HTLC-タイムアウトトランザクションは local_delayedpubkey
と revocationpubkey
を使用している。per_commitment_point
に基づいたトランザクションごとに変更がある。option_static_remotekey
と option_anchor_outputs
の場合、remotepubkey
への鍵ローテーションは適用されない。
鍵交換の理由は、失効されたトランザクションのトラストレスな監視を外部委託できるためである。そのような監視者は、たとえどのトランザクション ID を監視すべきかを知っていて、どの HTLC と残高が含まれているかを合理的に推測できたとしても、コミットメントトランザクションの内容を明らかにすることができるべきではない。しかし、コミットメントトランザクションごとのストレージを避けるために、監視者はペナルティトランザクションに必要なスクリプトを再作成するために使われる per_commitment_secret
, revocation_basepoint
, delayed_payment_basepoint
を受け取ることができる。従って、監視者は各ペナルティ入力に対する署名を与えられさえすればよい。
localpubkey
, local_htlcpubkey
, remote_htlcpubkey
, local_delayedpubkey
, and remote_delayedpubkey
Derivation
これらの鍵はかれらのベースポイントから足すことで生成される。
pubkey = basepoint + SHA256(per_commitment_point || basepoint) * G
対応する秘密鍵は同様に生成される。
privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)
remotepubkey
Derivation
option_static_remotekey
もしくは option_anchor_outputs
が交渉されている場合、remotepubkey
は単にリモートノードの payment_basepoint
であり、そうでない場合、リモートノードの payment_basepoint
を使用して計算される。
シンプルな派生は、たとえデータを失い、対応する per_commitment_point
を知らなくても、ノードがコミットメントトランザクションを支出することが可能ということを意味する。ウォッチタワーは、それらのうちの1つをオンチェーンで見た場合にのみ to_remote
出力を持っているそれに与えられたトランザクションを相関させることができたが、そのようなトランザクションは強制力を必要とせず、ウォッチタワーに渡されるべきではない。
revocationpubkey
Derivation
revocationpubkey
は見えない鍵である。ローカルノードがリモートノードに対して新しいコミットメントを作りたいと思った時、コミットメントのために新しい per_commitment_secret
を生成するために自身の revocation_basepoint
とリモートノードの per_commitment_point
を使用する。リモートノードがその per_commitment_secret
を明らかにした後、ローカルノードは revocationprivkey
を生成することができる。
per_commitment_point
は楕円曲線の掛け算で生成される。
per_commitment_point = per_commitment_secret * G
これはリモートノードの revocation_basepoint
から失効公開鍵を生成するために使用される:
revocationpubkey = revocation_basepoint * SHA256(revocation_basepoint || per_commitment_point) + per_commitment_point * SHA256(per_commitment_point || revocation_basepoint)
この構造は basepoint
を提供するノードも、per_commitment_point
を提供するノードも、どちらも他ノードの秘密なしで秘密鍵を知ることはできないことを保証する。
per_commitment_secret
がわかれば、対応する秘密鍵を導出することができる。
revocationprivkey = revocation_basepoint_secret * SHA256(revocation_basepoint || per_commitment_point) + per_commitment_secret * SHA256(per_commitment_point || revocation_basepoint)