作者:conduition
來源:https://conduition.io/scriptless/multi-party-submarine-swaps/
“潛水艇互換” 允許閃電網絡上的用戶免信任地將鏈內的 UTXO 置換成閃電通道中的餘額。它基本上就是用於閃電網絡的原子化互換,並且對閃電節點運營者極其有用(可用來重新平衡他們的通道,以及其他事項)。
隨著潛水艇互換變得日益重要和常見,也許是時候該看看如何更好地擴大潛水艇互換的吞吐量了 —— 如今,更多的對等節點和流動性提供者可以參與互換。
回顧
傳統的潛水艇互換是一種兩方的原子化互換,使用兩個哈希時間鎖合約(HTLC):一個部署在比特幣鏈內;另一個部署在閃電網絡中。
假設 Alice 想要賣出鏈內的比特幣,換成一筆閃電支付;而 Bob 想要使用他的閃電通道餘額來購買 Alice 的鏈內資金。
首先,Alice 要生成一個只有她自己知道的隨機秘密值 $s$ 。
Alice 和 Bob 構造一個 2-of-2 的託管地址:如果 Bob 知曉了 $s$ ,將擁有這個地址的完全花費權限,這是用一個哈希鎖條件來表達的;此外,在網絡達到特定的區塊高度 $B$ 之後,Alice 將獲得這個地址的完全花費權限。
這是一個用描述符來表達的案例:
tr( musig(<alice_pubkey>, <bob_pubkey>), { and(sha256(<hash>), pk(<bob_pubkey>)), and(after(<B>), pk(<alice_pubkey>)) })Alice 把自己的錢幣存入這個 2-of-2 託管合約,確信自己可以在區塊高度 $B$ 之後重新拿回資金,以及,Bob 當前是無法取走其中的錢的,因為只有她自己知道 $s$ 。
然後,Alice 給 Bob 一個閃電發票,其要求支付的數額與錢幣的面額一樣,並使用 $SHA256(s)$ 作為支付哈希值。Bob 可以支付這個發票,同時(通過 HTLC 的時間鎖)要求 Alice 最晚在區塊高度 $B - \Delta$ 就要釋放原像(領取支付),這裡的 $\Delta$ 是合理的時間延遲。如果 Alice 領取了 Bob 的閃電支付 HTLC(不論是與自己的通道對手完成協商,在鏈外釋放原像、領取資金;還是強制關閉通道,Alice 在鏈內曝光原像來領取),Bob 就會知道 Alice 的秘密值原像 $s$ ,然後他就可以轉走 上述託管合約中的資金。如果 Alice 很狡猾,到最後一刻,也就是區塊高度 $B - \Delta$ 才領取支付,Bob 也擁有 $\Delta$ 個區塊來知曉 $s$ 並使用它來領取 Alice 在鏈內的 HTLC(即上述合約)。
就是這樣!Bob 和 Alice 可以彼此置換鏈內和鏈外的錢幣,雙方都沒有機會欺詐對方。為了提升隱私性和效率性,Alice 和 Bob 可以合作:一旦 Bob 支付了閃電發票,雙方就使用 MuSig 來聯合簽名花費上述合約的交易、將資金轉移給 Bob(從而外人無法看出這是一筆 HTLC/潛水艇互換 交易)。
效率
一些潛水艇互換供應商,比如 Lightning Labs 的 Loop 服務,會批量處理他們的鏈內交易。在清掃他們收到的鏈內錢幣之時,一次清掃多個合約可以更好地將大量資金歸集到少量的 UTXO 中。在給潛水艇互換的託管合約地址注資時,也可以這樣做,每個輸出都給一個獨立的潛水艇互換合約注資。
但是,這裡依然有一個效率瓶頸,來自潛水艇互換協議自身的拓撲。我們有許多小節點(用戶),全部都跟一個潛水艇互換服務商(比如 Loop 或 Boltz)交互。用戶們完全不知道其他人的交易,所以每一筆潛水艇互換都是一個完全獨立的合約,發生在一個用戶和一個互換服務商之間。這就產生了浪費。
而每一個從鏈內錢幣到鏈外支付的潛水艇互換,都要求用戶發起一筆單獨的注資交易,因為用戶們不知道彼此,所以無法一起批量處理他們的主子交易。此外,每一個潛水艇互換都會創建一個獨立的注資交易輸出,所以,即使注資交易 得到了 批處理(就像 Loop 的鏈外到鏈內協議一樣),我們依然有 $n$ 個單獨的注入了資金的 HTLC 地址,可能要用 $n$ 筆額外的交易來解決。
擴容
我們可以通過將潛水艇互換從單一接單者協議轉變成 $n$-吃單者協議,來提高效率。 我們不再假設在每次互換中都是一個掛單人(maker)和一個吃單人(taker),而是假設有一個掛單人以及 $n$ 個吃單人,他們有能力進行帶有身份認證的通信,不論是通過 P2P 還是一個代理(比如掛單人)。這些參與者將通過將他們的 $n$ 個潛水艇互換合約聚合成一個注資 UTXO,一起執行一次免信任的原子化互換。
這會增加協議的複雜性和碎片化,但也能極大地提高鏈內效率。我們來看看這是怎麼做到的。
鏈內 -> 鏈外 互換的吃單人
我們先來看看 $n$ 個吃單人參與從鏈內到鏈外資金置換的情形。在這種情形下,交易的兩邊是:
- 吃單人:一組 $n$ 個吃單人,希望將小額的鏈內 UTXO 換成鏈外的閃電通道餘額。
- 掛單人:單個個人或企業,希望將閃電餘額換成鏈內資金。
不像傳統的潛水艇互換中那樣,吃單人們注資 $n$ 個鏈內單獨的鏈內託管地址 —— 而是一起注資到單個託管合約中,並且資金是在單筆交易中轉入的 —— 這個託管合約,要麼被掛單人花掉(如果合約執行順利的話),要麼退回給各位吃單人(如果合約執行不順利的話)。
- 掛單人生成 $n$ 個隨機秘密值 ${s_1, s_2, …, s_n}$(為每個吃單人安排一個)。
- 吃單人和掛單人一起創建一個 n-of-n 的 taproot 哈希鎖地址,如果掛單人可以揭曉 ${s_1, s_2, …, s_n }$,就能從這個地址中轉走資金。
以下是一個用描述符來表示的三重哈希鎖案例:
tr( musig( <taker1_pubkey>, <taker2_pubkey>, <taker3_pubkey>, <maker_pubkey> ), and( hash160(<hash1>), hash160(<hash2>), hash160(<hash3>), pk(<maker_pubkey>) ))使用 taproot 腳本,我們可以(通過聚合公鑰協議)使用 4-of-4 的內部公鑰,從而,在各方都配合的情況下,將體積很大的哈希鎖完全隱藏起來。我們使用 hash160 而費 SHA256 是為了節約區塊空間,同時保留在閃電網絡中以相同的秘密值(原像)使用 HTLC 的選擇。
- 吃單人們構造一筆 注資交易,將眾人的 UTXO 支付給上述多簽名地址(可能會有找零輸出)。吃單人們暫不簽名注資交易。
- 吃單人們構造一筆 超時交易,也即退還款項的交易。這筆超時交易將 注資交易 輸出中的資金返還給各吃單人。超時交易 必須帶有一個解鎖時間點為區塊高度 $B$ 的絕對時間鎖。
- 吃單人和掛單人一起簽名 超時交易。掛單人當然沒有意見,因為它帶有絕對時間鎖。
- 掛單人建立 $n$ 個閃電網絡 HTLC,每個 HTLC 為其中一個吃單人支付對應的互換金額。給吃單人 $i$ 的 HTLC 使用 $SHA256(s_i)$ 作為支付哈希值。各吃單人的互換金額可能不一樣。吃單人們還無法 領取 這些 HTLC ,因為只有掛單人知道每一個 HTLC 的原像 ${s_1, s_2, …, s_n }$ 。這些 HTLC 的絕對時間鎖必須至少是 $B + \Delta$ ,其中的 $\Delta$ 就是一個合理的時延(以區塊為單位)。
- 在所有的吃單人都在自己的通道中收到了 HTLC 之後,吃單人們一起簽名併發布 注資交易。
- 所有人等待注資交易得到區塊確認。
掛單人有三種選擇。
1. (鏈內)強制執行
掛單人可以使用原像 ${s_1, s_2, …, s_n }$ 在哈希鎖花費路徑中領取注資交易輸出。這樣的 申領交易 會在網絡中揭曉所有原像,從而吃單人們可以用這些原像來領取各自收到的 HTLC 中的資金。
即使掛單人拖到最後一刻才發佈 領取交易,吃單人們依然有 $\Delta$ 個區塊的時間窗口來領取各自通道中的 HTLC 中的資金。
2. (鏈外)合作
掛單人可以將 ${s_1, s_2, …, s_n }$ 中的每一個分別交給對應的吃單人。吃單人可以使用這些原像來領取自己通道中的 HTLC 。作為交換,吃單人們應該跟掛單人配合簽名一筆交易,從而將注資交易輸出中的資金釋放給掛單人。
即使有人拿原像兌換 HTLC 之後拒不交出簽名,掛單人依然可以在鏈內強制執行、取走注資交易輸出中的資金。
請注意,掛單人只交出 一部分 原像(而不是全部交付)是不理性的,因為實質上,每一個原像都是從掛單人處領取一些資金的權利。只要掛單人想在鏈上取走資金,就必然要揭曉所有的原像,而不是一部分。
3. 超時
掛單人可以選擇不揭曉任何原像。因此,吃單人將無法領取各自通道中的 HTLC 。當網絡達到區塊高度 $B$ 的時候,任何一個吃單人都可以發佈 超時交易,從而讓資金返還給各吃單人。再過 $\Delta$ 個區塊,他們各自通道中的 HTLC 也將過時。
性能
如果使用 $n$ 次傳統的潛水艇互換,鏈內的足跡最少也將是:
- $n$ 個不同的注資交易,每筆交易至少包含 1 個輸入和 1 個輸出
- $n$ 個不同的輸入,領走各託管地址中的資金(也許可以批處理成單筆交易)
在理想情況下,我們這裡的多方互換方法可以將($n$ 次互換)鏈內足跡減少到:
- 注資交易將至少有 $n$ 個輸入,至少 1 個輸出(可能會更多,因為有找零輸出)
- 1 個輸入,領取注資交易輸出(也許可以跟其它領取交易批量處理)
值得指出的是,如果 $n$ 較大,一些吃單人不配合,為了在鏈內領取注資交易輸出,掛單人可能需要在交易的見證輸出中發佈大量的 RMD160 哈希值和一個體積巨大的腳本。這可能會影響性能分析和 $n$ 的選擇。
鏈外 -> 鏈內 互換的吃單人
現在,來看看我們的方法在相反的情形中是如何工作的。
這時候,參與交易的兩種角色是:
- 吃單人:多個小體量的參與者,希望將閃電通道中的餘額換成小額的鏈內 UTXO 。
- 掛單人:單個個人或企業,希望將大額的鏈內 UTXO 換成閃電通道內的餘額。
這時候,掛單人不再像傳統的潛水艇互換那樣生成 $n$ 個單獨的鏈內託管地址,而是為一個託管地址注入資金,預期這個地址會在單個交易中花費 —— 要麼是發送資金給各吃單人(如果互換順利)、要麼是返回給掛單人(如果互換不順利)。
- 掛單人生成 $n$ 個隨機秘密值 ${s_1, s_2, …, s_n }$(為每個吃單人安排一個)。
- 吃單人和掛單人一起創建一個 1-of-n 的 taproot 哈希鎖地址
以下是一個用描述符來表示的吃單人數量為 3 的案例:
taker_joint_pubkey = musig( <taker1_pubkey>, <taker2_pubkey>, <taker3_pubkey>);tr( musig( <taker1_pubkey>, <taker2_pubkey>, <taker3_pubkey>, <maker_pubkey> ), { { and( hash160(<hash1>), pk(taker_joint_pubkey) ), and( hash160(<hash2>), pk(taker_joint_pubkey) ) }, and( hash160(<hash3>), pk(taker_joint_pubkey) ) })注意,在這個腳本中,吃單人是 3 個不同的哈希鎖花費條件的聯合收款方,也就是說,<hash1>、<hash2>、<hash3> 三個原像中的任何一個,都可以被吃單人用來領取其中的資金。
- 掛單人構造一筆 注資交易,它花費掛單人的 UTXO ,支付到上述 taproot 地址中(交易可能帶有詔令輸出)。掛單人暫不簽名這筆注資交易。
- 掛單人構造一筆 超時交易,它花費 注資交易 的輸出,將資金返回給掛單人。帶有解鎖時間點為區塊高度 $B$ 的絕對時間鎖。
- 吃單人和掛單人一起簽名 超時交易。吃單人願意接受,因為超時交易有絕對時間鎖。
- 吃單人們合作構造 $n$ 筆 領取交易,每一筆領取交易都使用注資交易輸出的不同哈希鎖花費分支來花費它、在吃單人們之間分割資金。吃單人們合作簽名所有 $n$ 筆 領取交易,沒有任何一筆會被公開,直到 ${s_1, s_2, …, s_n}$ 中的一個被揭曉。吃單人們都願意簽名這些交易,因為這些交易不會侵吞屬於他們自己的資金。每一個吃單人 $i$ 都必須獲得對應於自己的哈希值 $RMD160(SHA256(s_i))$一筆完全簽名的領取交易,從而,只要吃單人 $i$ 知曉了 $s_i$,就能夠發佈領取交易。
- 掛單人簽名並廣播 注資交易。
- 每個人都等待注資交易得到區塊確認。
- 吃單人們建立 $n$ 個 HTLC 並通過閃電網絡支付給掛單人,支付參與互換的金額,使用對應於自己的 $SHA256(s_i)$ 作為支付哈希值。吃單人們可能會使用不同的數額。每個 HTLC 的超時時間最晚也只能是 $B - \Delta$ ,這裡的 $\Delta$ 是合理的時間延遲(以區塊數量為單位)。掛單人必須等到所有的 HTLC 都送達之後,才能結算其中任何一個。
- 掛單人可以使用原像 ${s_1, s_2, …, s_n }$ 來結算任何一個 HTLC (也可以全部結算)。也就是任何一個吃單人都會獲得至少一個原像 $s_i$ 。請注意,理性的掛單人要麼會領取 所有的 HTLC,要麼 一個都不領。因為哪怕揭曉一個 $s_i$ ,都會讓吃單者們取走注資交易的輸出中的資金。
1. (鏈內)強制執行
任何一個吃單人 $i$,在知道原像 $s_i$ 之後,都可以發佈一筆 領取交易(是早前由所有吃單人簽名過的)。這筆原子化的交易會將掛單人的資金在吃單人之間公平分配。
即使掛單人希望等到其閃電通道內的 HTLC(根本上來自各位吃單人)超時之前的最後一刻才揭曉所有原像 ${s_1, s_2, …, s_n}$ ,也即最壞情況下,吃單人們也將擁有 $\Delta$ 個區塊的時間窗口來發布和確認一筆 領取交易。
2. (鏈外)合作
一旦掛單人領取了其閃電通道內所有的 HTLC,也即所有的原像 ${s_1, s_2, …, s_n}$ 都曝光了,掛單人可以跟吃單人們配合簽名一筆新版本的領取交易,使用那個 4-of-4 的內部公鑰。這讓他們可以藏起合約中的哈希鎖花費分支,提高隱私性和鏈內效率。
如果有人不簽名這個新版本的領取交易,某一個吃單人可以退回到發佈自己的 領取交易,只需在區塊高度 $B$ 之前(在 超時交易 變成有效交易之前)。
超時
如果掛單人什麼也沒做(不釋放原像),那麼來自吃單人的 HTLC 會在區塊高度 $B - \Delta$ 過期,從而給吃單人返回閃電通道餘額。然後,等到區塊高度 $B$ ,掛單人就可以用超時交易來清掃注資交易輸出。
如果吃單人在掛單人發佈 注資交易 之後不再響應,掛單人什麼都不需要做,只需等待區塊高度 $B$ ,然後發佈超時交易。
性能
如果使用 $n$ 次傳統的潛水艇互換,鏈內的足跡最少也將是:
- $n$ 個不同的託管輸出(也許可以批量處理為用一筆注資交易生成)
- $n$ 筆不同的交易來領取上述託管輸出,每筆交易都至少包含 1 個輸入和 1 個輸出(無法批量處理)
在理想情況下,我們這裡的多方互換方法可以將($n$ 次互換)鏈內足跡減少到:
- 1 個託管輸出(也許可以批量處理為一個較大體積的注資交易)
- 1 筆領取交易,帶有 1 個輸入和 $n$ 個輸出(在吃單人之間分配資金)
在部分吃單人或掛單人不合作的情形中,吃單人需要使用其中一個哈希鎖分支來領取鏈內資金。
減少騷擾
儘管將潛水艇互換拓展為多方協議是顯然有可能的,但這樣做可以獲得具體多少效率提升,是可以爭議的,因為這很大程度上取決於過程中的各方是否配合。從鏈內到鏈外的互換尤其如此,只要一個吃單人不合作,就可以迫使掛單人支付額外的手續費來(發佈一連串似乎毫無必要的哈希值和原像)領取資金。
同樣的騷擾攻擊在傳統的潛水艇互換協議中也存在,但在多方參與的環境中影響更大,因為一顆老鼠屎就能弄壞一鍋湯(讓互換對每個人都變得更貴)。
為了遏制來自吃單人的騷人,掛單人可以實現以下技術:
- 手續費。掛單人可以在閃電發票金額中加入手續費,要求吃單人支付(在從鏈外到鏈內的互換中);或者,可以減少在 HTLC 中支付給吃單人的數額(在從鏈內到鏈外的互換中)。這將激勵掛單人提供互換服務,並讓騷擾攻擊變得更加昂貴。
- 預存系統。掛單人可以強迫吃單人預先提供一個數額為互換金額的小比例的 HTLC 作為存款(使用 “HODL 發票”)。如果吃單人在互換過程中批核,則掛單人可以取消發票、退回存款。如果吃單人不配合,掛單人可以結算發票、取走存款,作為懲罰。這種存款不是免信任的 —— 掛單人可以無條件取走它;所以,需要一定程度的信任、責任感和聲譽。
- 匿名使用的 token 。吃單人可以從掛單人處購買一些 ecash token ,日後,將它兌換為與掛單人參與一次多方潛水艇互換的資格。
- 忠誠債券。這將允許匿名的掛單人或吃單人通過犧牲一些比特幣來換取一個永久的 掛單人/吃單人 身份,證明自己會誠實參與交易。
為了的工作
- 閃電網絡上的 “點時間鎖合約(PTLC)” 將允許顯著提高兩個方向上的多方潛水艇互換的鏈內隱私性和效率。那麼,基於 PTLC 的多方潛水艇互換會是什麼樣的?到底能獲得多少效率提升?
- 是否有可能執行 n-to-m 潛水艇互換,即 $n$ 個鏈內 UTXO 的賣方與 $m$ 個通過閃電支付來購買的買方達成交易?
(完)





