15. 閃電網路付款請求
在本章中,我們將了解_閃電網路付款請求_,或者它們更常見的名稱——閃電網路發票。
15.2. 簡介
正如我們在整本書中所學到的,完成閃電網路付款至少需要兩個資料:付款雜湊和目的地。由於閃電網路中使用 SHA-256 來實作 HTLC,這些資訊需要 32 位元組來傳輸。另一方面,目的地只是希望接收付款的節點的 secp256k1 公鑰。在閃電網路的背景下,付款請求的目的是將這兩個資訊從發送者傳輸到接收者。用於傳輸完成付款所需資訊的 QR 碼友好格式從接收者到發送者的方式在 BOLT #11:閃電網路付款發票協定 中描述。實際上,付款請求中傳輸的不僅僅是付款雜湊和目的地,還包含更多功能。
15.3. 閃電網路付款請求與比特幣地址的比較
人們第一次接觸閃電網路付款請求時經常問的一個問題是:為什麼不能使用普通的靜態地址格式?
要回答這個問題,你必須首先理解閃電網路作為支付方式與基礎層比特幣的不同之處。與可能用於進行潛在無限次數付款的比特幣地址(儘管重複使用比特幣地址可能會降低隱私性)相比,閃電網路付款請求應該只使用_一次_。這是因為向比特幣地址發送付款本質上使用公鑰密碼系統以一種只有該比特幣地址的真正「擁有者」才能贖回的方式「編碼」付款。
相比之下,要完成閃電網路付款,接收者必須向整個支付路徑(包括發送者)揭示一個「秘密」。這可以被解釋為使用一種特定領域的對稱密碼學,因為付款原像實際上是一個 nonce(僅使用一次的數字)。如果發送者嘗試使用相同的付款雜湊進行另一次付款,那麼他們將面臨資金損失的風險,因為付款可能實際上不會傳遞到目的地。可以安全地假設,在原像被揭示後,路徑中的所有節點都會永久保留它,然後與其轉發 HTLC 以在付款完成時收取路由費用,不如在那個時刻直接結算付款並獲得全部付款金額作為回報。因此,多次使用付款請求是不安全的。
原始閃電網路付款請求存在新的變體,允許發送者根據需要多次重複使用它們。這些變體翻轉了正常的付款流程,因為發送者在加密的洋蔥有效載荷中向接收者傳輸原像,而接收者是唯一能夠解密它並結算付款的人。或者,假設有一種機制允許發送者通常從接收者那裡請求新的付款請求,那麼可以使用互動式協定來允許一定程度的付款請求重複使用。
15.4. BOLT #11:閃電網路付款請求序列化 和解釋
在本節中,我們將描述用於編碼在閃電網路上完成付款所需資訊集的機制。如前所述,付款雜湊和目的地是完成付款所需的最少資訊。然而,在實踐中,還會傳輸更多資訊,如時間鎖資訊、付款請求過期時間,以及可能的鏈上備用地址。完整的規範文件是 BOLT #11:閃電網路付款發票協定。
15.4.1. 實踐中的付款請求編碼
首先,讓我們看看實際的付款請求是什麼樣子。以下是一個有效的付款請求,在建立時可用於完成主網閃電網路上的付款:
lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysx xatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatf hq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp
15.4.2. 人類可讀前綴
看看這個字串,我們可以挑出一部分可以用眼睛解析的內容,而其餘部分看起來只是一組隨機字串。人類可以在某種程度上解析的部分被稱為_人類可讀前綴_。它允許人類快速從付款請求中一眼提取一些相關資訊。在這種情況下,我們可以看到這是閃電網路主網實例的付款(lnbc),並且請求 2,500 uBTC(微比特幣),即 25,000,000 聰。後半部分被稱為資料部分,使用可擴展格式來編碼完成付款所需的資訊。
每個閃電網路實例版本(主網、測試網等)都有自己的人類可讀前綴(參見 BOLT #11 網路前綴)。這允許客戶端軟體和人類快速確定他們的節點是否可以滿足付款請求。
| 網路 | BOLT #11 前綴 |
|---|---|
主網 |
|
測試網 |
|
simnet/regtest |
|
人類可讀前綴的第一部分是付款請求金額的_緊湊_表達式。緊湊金額以兩部分編碼。首先,使用整數作為_基本_金額。然後跟著一個乘數,允許我們指定相對於基本金額的不同數量級增加。如果我們回到最初的例子,那麼我們可以取 2500u 部分並將其減少 1,000 倍,改為使用 2500m 或(2,500 mBTC)。作為經驗法則,要一眼確定發票的金額,取基本因子並乘以乘數。
目前定義的乘數完整列表見 BOLT #11 金額乘數。
| 乘數 | 比特幣單位 | 乘法因子 |
|---|---|---|
|
毫 |
0.001 |
|
微 |
0.000001 |
|
奈 |
0.000000001 |
|
皮 |
0.000000000001 |
15.4.3. bech32 和資料段
如果「不可讀」的部分看起來很熟悉,那是因為它使用了與今天 SegWit 相容的比特幣地址相同的編碼方案,即 bech32。描述 bech32 編碼方案超出了本章的範圍。簡而言之,這是一種編碼短字串的複雜方法,具有非常好的錯誤糾正和檢測特性。
資料部分可以分為三個部分:
-
時間戳記
-
零個或多個標記的鍵值對
-
整個發票的簽名
時間戳記以自 1970 年即 Unix 紀元以來的秒數表示。這個時間戳記允許發送者判斷發票有多舊,正如我們稍後將看到的,如果接收者願意,可以強制發票只在一段時間內有效。
類似於我們在 類型-長度-值格式 中學到的 TLV 格式,BOLT #11 發票格式使用一系列可擴展的鍵值對來編碼完成付款所需的資訊。因為使用了鍵值對,所以如果將來引入新的付款類型或額外的要求/功能,很容易添加新值。
最後,包含一個簽名,覆蓋由付款目的地簽署的整個發票。這個簽名允許發送者驗證付款請求確實是由付款目的地建立的。與未簽名的比特幣付款請求不同,這使我們能夠確保特定實體簽署了付款請求。簽名本身使用恢復 ID 編碼,這允許使用更緊湊的簽名來進行公鑰提取。驗證簽名時,恢復 ID 提取公鑰,然後對照發票中包含的公鑰進行驗證。
標記的發票欄位
標記的發票欄位編碼在發票的主體中。這些欄位表示不同的鍵值對,表達可能有助於完成付款的額外資訊或完成付款_所需_的資訊。因為使用了 bech32 的輕微變體,這些欄位中的每一個實際上都在「基數 5」域中。
給定的標記欄位由三個組成部分組成:
-
欄位的
type(5 位元) -
欄位資料的
length(10 位元) -
data本身,大小為length * 5 位元組
所有目前定義的標記欄位的完整列表見 BOLT #11 標記的發票欄位。
| 欄位標記 | 資料長度 | 用途 |
|---|---|---|
|
|
SHA-256 付款雜湊。 |
|
|
256 位元秘密,通過減輕中間節點的探測來增加付款的端對端隱私。 |
|
可變 |
描述,付款目的的簡短 UTF-8 字串。 |
|
|
目的地節點的公鑰。 |
|
|
表示付款本身描述的雜湊。這可用於承諾長度超過 639 位元組的描述。 |
|
可變 |
付款的過期時間,以秒為單位。如果未指定,預設為 1 小時(3,600)。 |
|
可變 |
用於路由中最後一跳的 |
|
可變 |
備用鏈上地址,如果無法通過閃電網路完成付款,則用於完成付款。 |
|
可變 |
一個或多個條目,允許接收者為發送者提供額外的臨時邊以完成付款。 |
|
可變 |
一組 5 位元值,包含完成付款所需的功能位元。 |
欄位 r 中包含的元素通常被稱為_路由提示_。它們允許接收者傳達一組額外的邊,可能有助於發送者完成付款。當接收者有一些/全部私有通道,並希望引導發送者進入通道圖的這個「未映射」部分時,通常會使用提示。路由提示有效地編碼與正常 channel_update 訊息相同的資訊。更新本身被打包成一個具有以下欄位的單一值:
-
邊中出站節點的
pubkey(264 位元) -
「虛擬」邊的
short_channel_id(64 位元) -
邊的基本費用(
fee_base_msat)(32 位元) -
比例費用(
fee_proportional_millionths)(32 位元) -
CLTV 過期增量(
cltv_expiry_delta)(16 位元)
資料段的最後部分是一組功能位元,向發送者傳達完成付款所需的功能。例如,如果將來添加了與原始付款類型不向後相容的新付款類型,那麼接收者可以設定一個_必需_功能位元來傳達付款者需要理解該功能才能完成付款。
15.5. 結論
正如我們所看到的,發票遠不止是金額請求。它們包含有關_如何_進行付款的關鍵資訊,例如路由提示、目的地節點的公鑰、增加安全性的臨時金鑰等等。