作者:ZmnSCPxj
引言
我們這樣定義 LSP(閃電網絡服務商)的 “最後一公里” 問題:
- 從閃電網絡接收自己的第一筆比特幣的新用戶必須為 “入賬流動性(收款額度)” 支付。
- 與獲取流動性相關的區塊鏈操作必須在多個新用戶間分攤,才能讓每個用戶的成本降下來。
除了上述問題,我們的解決方案還必須受到下列條件的約束:
我們必須保證 LSP 不能偷盜資金,即,僅僅實現 “只需一個誠實參與者” 的安全假設 是不夠的,除非每個終端用戶都可以為自己擔當那個誠實參與者。
必須無需變更區塊鏈的共識。
- 比特幣區塊鏈協議在實踐中已經定型(ossified)。因為計劃中每 4 年發生一次的增發減半會導致比特幣回來的突然升高,進而導致對比特幣興趣的突然增加,大量的新用戶會從成為跟比特幣的共識有利益相關的實體。當上一批用戶被說服了要變更共識的時候,新的一批用戶又進來了,他們也必須同意相同的共識變更。如果一項共識變更無法在短於減半週期的時間裡獲得實際共識,它就可能根本不會發生,從而導致實踐中的協議定型(更小、更易於處理的變更可能依然能通過,但更復雜的變更,比如 “限制條款(covenant)”,可能永遠不會獲得共識)。
當 LSP 必須重新分配資金的時候,我們必須能夠對付少量終端用戶離線的情形。
- 隨著共享同一個 UTXO 的用戶數量增加,出現一個乃至多個用戶離線情形的概率也會上升。因此,當覆蓋大量終端用戶時,應對部分終端用戶離線的能力是必要的。
- 已經證明,運行在移動端的軟件可以通過 Android 或 iOS 的應用通知機制喚回到線上,因此,在現實中,移動客戶端的在線是有很高保證的。不過,移動端依然可能偶然斷網,所以,它們的運行時間依然不會像非移動設備那麼好。因此,整套機制依然要能應對少量用戶離線的情形。
上述約束立即排除了 Ark 和 BitVM2 橋。如果沒有限制條款,這兩者都有 “至少一個誠實參與者” 假設,而依照上文的推理,限制條款在現實中不會激活(OP_CTV
提議在 2020 年就已經大體完成了,但到今天(2024年)也還未獲得共識;這已經超過了減半週期,所以永遠不能獲得共識了;SIGHASH_NOINPUT
的遭遇甚至更加糟糕)。兩者都可以取消 “至少一個誠實參與者” 假設,僅當 LSP 需要重新分配資金時所有終端用戶都同時在線;這就違反了上述最後一個約束。
在本文中我會提出一種叫做 “SuperScalar” 的構造,實際上,是一種分層超時樹結構的 Decker-Wattenhofer 通道工廠。
配方
首先,我要(希望是)簡單介紹一下組合出這種構造的三個模塊:
- Decker-Wattenhofer 基於遞減
nSequence
的鏈下更新機制; - “超時樹(timeout tree)”,尤其是使用全體簽名來模擬
OP_CTV
的變種,我稱為 “超時簽名樹”; - 築梯法。
請隨意跳過你已經很熟悉的部分。
Decker-Wattenhofer
Decker-Wattenhofer 遞減 nSequence
機制是一種鏈下的密碼貨幣系統,允許一組利益相關的用戶對一些狀態變更達成一致,而無需每一個狀態變更都發布到區塊鏈上(這就是它被歸類為 “鏈下” 機制的原因)。這聽起來跟 Poon-Dryja 機制(譯者注:即閃電通道機制)很像,但有如下區別:
- 參與者數量:
- Poon-Dryja 機制嚴格限定只能兩方參與;
- Decker-Wattenhofer 遞減
nSequence
機制可以容納任意數量的參與者;
- 狀態變更的次數:
- Poon-Dryja 機制理論上可以無限次更新狀態(在現實的部署中,比如閃電網絡的 BOLT 規範,會限制狀態更新的次數,但這個上限是以十億次為單位的,因此可以說也是無限的)。
- Decker-Wattenhofer 遞減
nSequence
機制允許的狀態更新次數更少。單個無連鎖(chained)的構造可以提供少量次數的狀態更新(少於 100 次,並且在實踐中,每個有連鎖的機制只能提供 4 次或 2 次)。標準的提議是連鎖多個這樣的構造,實際上就是讓每一個被連鎖的構造中可發生的狀態變更次數倍乘(例如,連鎖 3 個構造,每個構造都允許發生 4 次變更,那麼就允許變更 4 x 4 x 4 = 64 次)。
- 單方面退出的規模和便利性:
- Poon-Dryja 機制只需要一筆承諾交易就可以單方面退出,同時需要額外一筆交易來回收資金。從發起承諾交易到允許取回資金之間的時延是一個常量。
- Decker-Wattenhofer 遞減
nSequence
機制需要一筆 “彈出(kickoff)” 交易來開啟單方退出流程,然後每一層都需要額外一筆帶有時延的交易。如果連鎖多層這樣的構造來增加允許的狀態變更次數,單方面退出時候所需的額外交易數量也會增加,所以所需的區塊空間在實際中是O(log N)
,其中 N 是可支持的狀態變更次數。在資金可以取回之前,每一層的交易都有可變的時延。
Decker-Wattenhofer 機制和 Poon-Dryja 機制都無需共識變更就可以在比特幣中實現。
跟 Poon-Dryja 機制一樣,Decker-Wattenhofer 遞減 nSequence
機制具有一個鏈上 UTXO 作為 “注資輸出點(funding outpoint)”。這個輸出點是一個簡單的 n-of-n 多簽名裝置,由簽名狀態變更的所有簽名人組成。
如果是一個單層的 Decker-Wattenhofer 遞減 nSequence
機制,那就只有兩筆交易:
- 一筆 “彈出” 交易,花費注資輸出點,併產生一個 n-of-n 多簽名輸出
- 一筆 “狀態” 交易,花費彈出交易的輸出,並且由
nSequence
要求一個具體的相對時間鎖。該交易的輸出就是被所有簽名人一致同意的狀態。
對於最初的狀態,“狀態” 交易的 nSequence
是設計好的最大相對時間鎖。 舉個例子,對一個意在允許 4 次狀態變更的設計而言,合理的初始狀態是 432 個區塊的相對時間鎖。
在變更狀態的時候,如果所有簽名人都同意一個新狀態,他們就創建一筆花費注資輸出點的新的狀態交易,但帶有比上一筆狀態交易更短的 nSequence
相對時間鎖。舉個例子,對一個允許 4 次狀態更新的設計來說:
狀態編號 | 相對時間鎖(以區塊數量為單位) | 備註 |
---|---|---|
0 | 432 | 初始狀態 |
1 | 288 | |
2 | 144 | |
3 | 0 | 最終狀態;這個實例只能結束了 |
這就是它為什麼叫做 “遞減 nSequence
”機制;每次簽名人們要批准一個新的狀態時,表示新狀態的交易就會使用一個更小的 nSequence
數值,直到它變成 0 。
因為最新的狀態總是具有更短的相對時間鎖(相比任何舊狀態),它就總是可以比較早的狀態更快獲得確認。這一機制保證了,假設區塊鏈層不擁堵,最新的狀態就是在單方退出場景中會得到確認的那一筆交易。
nSequence
相對時間鎖的差值需要足夠大,以使各方都可以合理假設,即使在擁堵狀態下,最先的狀態也能比舊的狀態先一步得到確認。因此,上文的案例使用的差值是 144 個區塊。
如上文所說,這樣的一套構造,只能更新少量幾次狀態,就會達到 “最終狀態”。因此,Decker-Wattenhofer 建議在實際使用中連鎖多個這樣的構造。整個鏈條的第一個構造有一個輸出,是簽名人的 n-of-n 多簽名裝置;這個輸出又作為下一個構造的輸入,以此類推。只有最後一個構造具有狀態交易(有多個輸出)、表示整個系統中的資金的最新狀態。
實際上,上一個構造的 “狀態” 交易是通過下一個構造的 “彈出” 交易給省去(cut-through)了。
連鎖的 Decker-Wattenhofer 機制就類似於多個數位的倒計時器。每當批准了一個新狀態,鏈條中最後一個構造 —— 離注資交易最遠的那個構造 —— 就倒數一次。不過,要是最後一個數位已經變成了 0,那麼就在倒數第二個數位上倒數一次,並將最後一個數位重置為最大的 nSequence
。 類似地,要是倒數第二個數位變成了 0,那麼就在倒數第三個數位上倒數一次,然後將後續的數位都重置為最大的 nSequence
。以此類推。
實際上, 鏈條中的最後一個構造是最有可能發生狀態變更的(每次狀態更新都要變更它),而鏈條中的第一個構造是最不可能發生變更的。
Initial state nSequence nSequence +----+------+ +-----+------+ +-----+-----------+funding -->| |n-of-n|-->| 432 |n-of-n|-->| 432 |...state...| +----+------+ +-----+------+ +-----+-----------+ kickoff tx state tx state tx======> nSequence nSequence +----+------+ +-----+------+ +-----+-----------+funding -->| |n-of-n|-->| 432 |n-of-n|-->| 288 |...state...| +----+------+ +-----+------+ +-----+-----------+ kickoff tx state tx state tx======> nSequence nSequence +----+------+ +-----+------+ +-----+-----------+funding -->| |n-of-n|-->| 432 |n-of-n|-->| 144 |...state...| +----+------+ +-----+------+ +-----+-----------+ kickoff tx state tx state tx======> nSequence nSequence +----+------+ +-----+------+ +-----+-----------+funding -->| |n-of-n|-->| 432 |n-of-n|-->| 0 |...state...| +----+------+ +-----+------+ +-----+-----------+ kickoff tx state tx state tx======> nSequence nSequence +----+------+ +-----+------+ +-----+-----------+funding -->| |n-of-n|-->| 288 |n-of-n|-->| 432 |...state...| +----+------+ +-----+------+ +-----+-----------+ kickoff tx state tx state tx
超時樹
超時樹是一種結合了 OP_CTV
樹和超時的機制。
在沒有 OP_CTV
的時候,可以使用一種變種:利用所有參與者的簽名來強制實施 OP_CTV
限制條款。這一變種(我稱為 “超時簽名樹” )是我要解釋的重點。此外,我們還考慮了單個 LSP 向自己的客戶提供這樣一種機制的情形。
在超時簽名樹上,一個 LSP L
可以向一組客戶提供閃電通道。單個得到確認的鏈上 UTXO 就可以為與不同客戶開設的多條通道提供保證。
在初始化階段,這個 LSP 先創造一棵由交易組成的樹。在非葉子的節點的輸出中,其子樹上的客戶會跟 LSP 一起組成一個 n-of-n 的多簽名裝置。這是標準的交易樹構造,但超時樹還添加了一個替代性的花費條件:LSP 可以在一段時間之後獨自花費資金。同樣的替代條件也存在於注資輸出點中。
舉個例子,如果 LSP L
有 8 個客戶,標記為 A
到 H
,然後大家會形成一棵超時樹。在(將得到鏈上確認的)注資輸出點上會有這些條件:
A & B & ... & H & L
L & CLTV
那麼,整棵樹看起來就是這樣的:
+--+---+ | |A&L| LN channel +>| +---+ | | |B&L| LN channel +--+----------+ | +--+---+ | | (A&B&L) |-+ | |or(L&CLTV)| +--+---+ +>| +----------+ | |C&L| LN channel +--+----------+ | | | (C&D&L) |-->| +---+ | |(A&..&D&L)| | | |or(L&CLTV)| | |D&L| LN channel | |or(L&CLTV)|-+ +--+----------+ +--+---+funding-->| +----------+ | |(E&..&H&L)|-+ +--+----------+ +--+---+ | |or(L&CLTV)| | | | (E&F&L) | | |E&L| LN channel +--+----------+ | | |or(L&CLTV)|-->| +---+ +>| +----------+ | |F&L| LN channel | | (G&H&L) | +--+---+ | |or(L&CLTV)|-+ +--+----------+ | +--+---+ | | |G&L| LN channel +>| +---+ | |H&L| LN channel +--+---+
(譯者注:這棵樹也可以從葉子往樹根看。每個葉子都是 LSP 跟一個客戶的閃電通道;而葉子節點以上,每一個節點都是下面所有參與者的多簽名裝置,外加 LSP 的超時花費裝置。)
這個超時條件迫使所有的客戶都要在超時之前回到線上,並退出這樣的構造。退出可以是單方面的,也可以跟 LSP 配合。
在合作式退出情形中,客戶端可以直接將自己在超時樹上的通道中的所有資金通過閃電網絡轉移出去,可以通過互換服務轉為鏈上資金,也可以轉給同一個 LSP 的新的超時樹,還可以轉給另一個 LSP。
單方面退出就意味著,要把從樹根到自己的閃電通道輸出路徑上的交易都公開,然後再單方面退出閃電通道(預期是 Poon-Dryja 通道)。
使用樹結構的好處在於,單方面退出的代價比較小;一個客戶要退出,僅僅只需發佈 O(log N)
筆交易,然後大部分其他客戶都可以留在樹上。如果不使用樹結構,那麼一個客戶單方面退出就會導致所有客戶都單方面退出。
超時條件的好處在於,它鼓勵所有客戶同時退出,有可能是合作式退出,然後 LSP 就只需要發起一筆只有一個輸入的交易(使用注資輸出點中的 L & CLTV
條件),就可以從構造中清掃資金。即使一些客戶也想要單方面退出,許多資金也可以通過每一箇中間輸出的 L & CLTV
條件來取回。
階梯式
許多金融機構都提供一種金融合約:儲戶可以存一些錢進去,但在一段時間內無法取回,哪怕想取回一部分也不行;到期之後,儲戶可以取回原本的所有資金,外加一筆利息。這種合約也是不可轉讓的。這樣的合約有許多名稱:
- 存款證明(美國)
- 有保證的投資證書(加拿大)
- 定期存款(其它國家)
這樣的合約是不靈活的;前面已經說了,到期之前你都無法取出資金。但是,精明的投資者會將自己可使用的自己分配到多個這樣的合約中,讓到期的日子錯開一個月、一年。這種技術叫做 “築梯法”。
舉個例子,一個投資者可能有三份這樣的合約,到期時間分別是 2024 年 12 月,2025 年 12 月以及 2026 年 12 月。在 2024 年 12 月的時候,第一份合約到期,然後這名投資人可以取出部分資金,然後將剩餘資金重新投入到一份 2027 年 12 月到期的新合約中;或者,添加更多資金、一起投入到新合約中;或者,不再簽訂新合約,從而結束築梯。
築梯法給投資人提供了每月或者每年一次改變投資額度的能力,具體取決於你的階梯有多寬。因此,即使基礎的合約是不靈活的,築梯法也能讓投資者重新拿回少許靈活性,同時保持長期定期存款的優勢。
SuperScalar 機制
築梯法超時樹結構的 Decker-Wattenhofer 通道工廠就是上述三種元素的結合。
超時樹結構的 Decker-Wattenhofer 通道工廠
首先,讓我們演示這兩者的結合;我們會在後文的一個小節中專門把築梯法加進去。
假設一個 LSP L
有 8 個客戶,編號從 A
到 H
。因此,注資輸出點有以下兩種花費條件:
A & B & ... & H & L
L & CLTV
在初始化的時候,這個 LSP 要安排下列交易讓客戶簽名,其中注資(funding)交易是一個 n-of-n 的多簽名交易(由 A...H
和 L
組成):
nSequence +---+---+ | |A&L| LN channel | +---+ +-->|432|B&L| LN channel | | +---+ | | | L | | +---+---+ | | +---+---+ | | |C&L| LN channel +--+-----+ | | +---+ nSequence | |A&B&L|-+ +>|432|D&L| LN channel +---+----------+ +>| +-----+ | | +---+ | |(A&..&D&L)| | | |C&D&L|---+ | | L | +--+---------+ | |or(L&CLTV)|-+ +--+-----+ +---+---+funding->| |A&...&H&L|->|432+----------+ +--+---------+ | |(E&..&H&L)|-+ +--+-----+ +---+---+ kickoff tx | |or(L&CLTV)| | | |E&F&L|---+ | |E&L| LN channel +---+----------+ +>| +-----+ | | +---+ state tx | |G&H&L|-+ +>|432|F&L| LN channel +--+-----+ | | +---+ kickoff | | | L | tx | +---+---+ | | +---+---+ | | |G&L| LN channel | | +---+ +-->|432|H&L| LN channel | +---+ | | L | +---+---+ state tx
基本上,從一組客戶建立一棵交易樹的規則,利用了 “從葉子到樹根” 的構造順序:
- 首先,根據自設的叉數,將客戶分散到葉子節點上(上例中的叉數是 2)。
- 這些葉子交易的輸出是 LSP
L
與相應客戶的通道,還有一個額外的輸出(一筆額外的資金)由L
持有。
- 這些葉子交易的輸出是 LSP
- 葉子節點總是狀態交易。
- 它們有遞減的
nSequence
。
- 它們有遞減的
- 根據所需的叉數,建立這些葉子在樹上的父節點。
- 狀態交易的父交易是彈出交易。
- 它們的輸出僅僅是相應子交易的所有者的 n-of-n 多簽名。
- 彈出交易的父交易是狀態交易。
- 狀態交易輸出除了有其分支交易的所有者的 n-of-n 多簽名花費條件以外,還有一個替代性的
or (L & CLTV)
花費條件。 - 狀態交易的輸入有遞減的
nSequence
。
- 狀態交易輸出除了有其分支交易的所有者的 n-of-n 多簽名花費條件以外,還有一個替代性的
- 狀態交易的父交易是彈出交易。
- 重複上一步,直至得到一個根節點。
- 如果最終的根節點是一筆狀態交易,那麼就在前面再添加一筆單輸入、單輸出的彈出交易。否則,直接使用這個根節點作為第一筆彈出交易。
- 在叉數為 2,客戶數量為 8 時,根節點恰好是一筆彈出交易。
- 如果例子中的客戶數量提高到 16,那麼一次單方面退出所需發佈的交易數量就是 4 筆,另外還需要在閃電通道中單方面退出的交易。
在樹的分層中交替使用彈出交易和狀態交易的原因,我們會在後文解釋。
糟糕,A 需要入賬流動性!
假設 A 在上述樹結構中、她和 L
的通道中用盡了收款額度。那麼 L
該如何為 A
提供流動性,而免於發起鏈上交易呢?
LSP 可以喚醒 B
—— 並且只需要 B
(假設A
在請求更多收款額度時已經上線)—— 以更新包含 A & L
通道和 B & L
通道的葉子節點。因為這個葉子節點只包含 A
、B
、L
的資金,所以只需要這三位在線;因此,這個機制可以更好地應對部分參與者離線、而 A
需要額外收款額度的情形。
當然,如果 B
無法在線,那麼 LSP 就必須嘗試別的辦法,例如,在鏈上發起交易。這可能產生需要支付的鏈上手續費,LSP 會向 A
收取。
假設 B
回到了線上。那麼,L
可以用自己專用的資金向 A & L
的通道注入資金。而無需要求客戶C...H
在線。
當然,可能這個葉子中 L
自有的資金已經花完了,或者這個葉子已經到搭了最終的狀態(即,nSequence = 0
)。這時候,這個 LSP 可以沿著樹向上、找到更高層的狀態交易、喚醒其他客戶,以將其它葉子上的專有資金轉移給 A
,並重設該層以下的節點的 nSequence
。這增加了需要同時在線的客戶的數量,但依然不要求 所有 客戶都在線。
實際上,不論什麼時候一些客戶用盡了入賬流動性,最末端的狀態交易都是最有可能要更新的。不過,如果一個葉子中的 L
專有資金已經用盡,那麼就需要更新更上層的狀態交易,讓 LSP L
可以從別的葉子分配資金給 A
。
出事了,A 要退出!
假設 A
決定單方面退出。原因可能多種多樣;重要的事情是,LSP 的任何客戶都應該有能力單方面退出,並且需要發佈的交易應該儘可能少。這種保證防止了 LSP 跑路,還保證了用戶的自主性和資金控制。
為了讓 A
退出,我們首先需要讓 A & L
通道的注資輸出點得到確認,然後使用標準的 Poon-Dryja 通道單方退出程序完全退出。因此,A
必須先公開從樹根到自己的通道注資輸出點的交易,如下圖:
nSequence +---+---+ | |A&L| LN channel | +---+ +-->|432|B&L| LN channel | | +---+ | | | L | | +---+---+ | state tx | | +--+-----+ | nSequence | |A&B&L|-+ +---+----------+ +>| +-----+ | |(A&..&D&L)| | | |C&D&L| +--+---------+ | |or(L&CLTV)|-+ +--+-----+funding->| |A&...&H&L|->|432+----------+ kickoff +--+---------+ | |(E&..&H&L)| tx kickoff tx | |or(L&CLTV)| +---+----------+ state tx
不過,我們還要注意,得到確認的彈出交易的任何輸出都必須被一筆得到確認的狀態交易花掉。這是因為狀態交易都有 nSequence
,而更小 nSequence
相對時間鎖的交易應該在更大 nSequence
的交易之前得到確認,否則 Decker-Wattenhofer 機制就崩潰了(可能會讓更舊的狀態先得到確認)。
因此,在 A
想要退出的情形中,不僅同一葉子上的客戶(B
)要在無意中退出,上一層狀態交易中的鄰居 C
和 D
也要退出。
nSequence +---+---+ | |A&L| LN channel | +---+ +-->|432|B&L| LN channel | | +---+ | | | L | | +---+---+ | | +---+---+ | | |C&L| LN channel +--+-----+ | | +---+ nSequence | |A&B&L|-+ +>|432|D&L| LN channel +---+----------+ +>| +-----+ | | +---+ | |(A&..&D&L)| | | |C&D&L|---+ | | L | +--+---------+ | |or(L&CLTV)|-+ +--+-----+ +---+---+funding->| |A&...&H&L|->|432+----------+ kickoff state tx +--+---------+ | |(E&..&H&L)| tx kickoff tx | |or(L&CLTV)| +---+----------+ state tx
這也解釋了為什麼我們在樹上要交替使用 “狀態” 交易和 “彈出” 交易,而不像一般的 Decker-Wattenhofer 構造那樣,只有第一筆交易才是 “彈出” 交易。如果我們模仿一般的結構,那麼只要一個客戶需要退出,下游的所有狀態交易(可能各有不同的 nSequence
相對時間鎖)都必須發佈,不然 Decker-Wattenhofer 機制就有被打破的風險。穿插的 “彈出” 交易正是為了充當後端,保證一個參與者單方面退出時只需要發佈 O(log N)
筆交易,而不是整棵樹 O(N)
。
這也是為什麼彈出交易的輸出不需要時間鎖分支 L & CLTV
。彈出交易的輸出必須被該輸出的最新狀態交易花掉,而狀態交易已經有時間鎖分支了。
在上面的例子中,B
、C
和 D
依然可以在自己的通道中轉發 HTLC,但不再能便宜地向 L
購買額外的收款額度。相反,L
將需要在鏈上拼接額外的入賬流動性,這會更貴。(也就是說,一個參與者退出不會導致 所有 參與者都退出;但依然會導致其他 一些 參與者部分退出;“部分” 的意思是他們的通道還在,但不能便宜地獲得收款額度了。)
不過,從 E
到 H
的客戶依然能夠用上述機制購買入賬流動性,因為他們所在的樹並沒有被髮布到鏈上,而且依然能在鏈下更新。此外,得到超時窗口要結束的時候,這些客戶可以通過閃電網絡發起合作式退出(在他們跟 L
的通道中也不會再剩下資金),然後 L
就可以通過狀態交易的 L & CLTV
分支清掃資金、讓資金重新流動起來。
築梯法
現在,加入第三種元素。
從 LSP L
的觀點看,上述機制是一項投資。L
的希望是投資中可以賺取回報,手段有:
- 閃電網絡路由費
- 在鏈下更便宜地售賣流動性
- 為維護整個機制而收取的手續費
此外,由於超時分支的存在,在到期之前,LSP 無法輕易取回資金。
因此,一個超時樹結構的 Decker-Wattenhofer 實例非常像一筆定期存款,從 LSP 的角度看。
而就像我在前面提到的,精明的投資者會使用多個定期存款合約來築梯,從而獲得一些資金分配上的靈活性。
LSP 自身可以運行多個超時樹結構的 Decker-Wattenhofer 實例,面對不同的客戶、使用不同的條款,就像傳統金融中的定期存款階梯。在一個實例到期的時候,這個 LSP 可以開啟一個新的實例、邀請即將結束的實例中的用戶參加新的實例,還可以為轉移收費。然後這個 LSP 就可以通過超時分支,在鏈上從即將結束的實例中回收資金。他會從路由費、銷售收款額度和轉移到新實例的特權中獲得收入,而這些收益會保留在閃電通道中。
舉個例子,一個 LSP 可以同時運行 30 個 Decker-Wattenhofer 工廠,每一天都會有一個工廠到期。當一個工廠即將結束的時候,他可以邀請該工廠中的客戶進入一個新的工廠。這個 LSP可以將過期工廠中的錢投入新工廠、創建一個新的為期 30 天的工廠。然後,客戶也可以從即將過期的工廠中轉出資金到新工廠中。等到所有的客戶都已經從即將過期的工廠中退出、合約完結,這個 LSP 可以直接花費整個 UTXO,交易只有一個輸入和一個輸出。
在下面這個具體的例子中,一個 LSP 構築了由 9 個超時樹 Decker-Wattenhofer 工廠組成的階梯。每一級階梯都有 7 天的 “活躍期” 和 2 天的 “結束期”。在結束期,客戶可以加入在那兩天中新建的工廠之一、將自己的資金轉移到新工廠的一條新通道中。這給了用戶一點餘地;如果他們錯過了第一天,還有機會在第二天轉移。在實際的部署中,我會建議使用 30 天的活躍期和 3 天的結束期;因此,一個 LSP 將需要同時維護 33 個工廠。理想情況下,每天都會發生一筆只有一個輸入和一個輸出的交易;雖然如果某個客戶不上線的話,這個 LSP 就需要發佈從樹根到該客戶的輸出的交易,這會增加需要發佈的鏈上的交易。
Legend: ===== Active Period ::::: Dying PeriodDay | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 ===================================:::::::::: <---- each of this a factory ===================================:::::::::: ===================================:::::::::: ===================================:::::::::: ===================================:::::::::: ===================================:::::::::: ===================================:::::::::: ===================================:::::::::: Client can move ^ ===================================:::::::::: funds from first -----------+----^ ===================================:::::::::: factory to either of ^ these two new LSP uses the funds of the factories first factory to build this factory
不幸的是,因為缺乏限制條款,客戶們需要在 LSP 構造新工廠的時候同時在線。如果他們錯過這個時間,就需要在結束期的下一天再次嘗試;如果他們在結束期的最後一天也錯過了,他們就必須退出,要付出所有的代價。OP_CTV
允許 LSP 搶先將客戶添加到新的工廠中,不需要客戶立即回到線上(客戶可以在結束期的 任何 時間回到線上,而不像無限制條款情形中,客戶需要在結束期內的 一個 具體時間上線)。不過,這也有缺點,如果那些客戶 真的 退出,而不是加入新工廠,LSP 將被迫在下一個活躍期鎖定資金;而且,因為這個客戶已經離開了,LSP 就不能獲得 TA 的簽名,也就無法利用 TA 的簽名在鏈下重新分配資金 ,這會影響樹上的相鄰客戶(即,同一棵樹上的 其他 用戶也將將無法便宜地買到入賬流動性,因為 LSP 搶先將客戶加到樹上、但這個客戶卻退出了,(可以假設)不會再與 LSP 有什麼聯繫)。
定期從舊工廠轉移到新工廠的要求,也為流動性費用的定價提供了一個便利的節奏。
結束期越長,LSP 需要額外投入的資金就越多。這些資金也需要有回報,因此,延長結束期需要增加向客戶收取的手續費。這是一個簡單的 方便 vs. 代價的考量。
為了降低客戶不得不單方面退出的概率,LSP 可以提供一種合作退出服務:客戶將工廠內的資金置換成鏈上資金(使用標準的 HTLC,也即極為常見的 鏈下-鏈上 互換)。這讓客戶可以退出到鏈上,而無需發佈單方退出交易;單方面退出會導致更多 UTXO 發佈,也會增加 LSP 在相關工廠過期後管理鏈上資金的成本。
現實考量
希望我已經解釋清楚了築梯法超時樹結構的 Decker-Wattenhofer 通道工廠的概念,讓我們轉向跟這個機制相關的現實考量。
為什麼要有 L ?
在這個提議中,每一個葉子都帶有一個專屬於 LSP L
的輸出,可以用來動態向需要收款額度的客戶分配資金。
這就帶來了一個問題:我們能夠取消這個 L
輸出嗎?
舉個例子,假設所有的葉子都僅僅由通道組成。所以 A
和 B
就會有一筆葉子交易,包含了通道 A & L
和 B & L
。
假設 A & L
用盡了 A
的收款額度,而 B & L
擁有收款額度。那麼 LSP 可以從跟 B
的通道中移動資金到跟 A
的通道中。
問題在於,這不是激勵兼容的。B
沒有激勵參與這個新狀態的簽名:因為他會損失有價值的東西,收款額度!
假設 A
和 B
都是在兩個方向上都有大量閃電支付的用戶。如果 B
簽名了損失收款額度的交易,那麼只要他先遇到一個出賬支付的峰值,稍後遇到一個入賬支付的峰值,就不得不向 LSP 購買更多收款額度。如果 A
已經用完了可以從狀態變更中獲得的收款額度,那麼 LSP 就不得不移動到上一層、從其他客戶那裡獲得更多流動性。這就需要更多的客戶回到鏈上,從而也提高了其中一些客戶不能按需在線的概率,這就強迫 LSP 發起昂貴的鏈上支付來讓 B
獲得更多收款額度。顯然,更高的支出也會被 LSP 轉加給客戶。
那麼,你可能會提議,LSP 可以給 B
支付、購買他手上的資金。
問題在於,最初,收款額度是 B
從 LSP 手上買的。 LSP 為了入賬流動性而給B
支付,實際上相當於給一項已經付款的商品退款。你可以想象,退款總是糟糕的客戶體驗;作為流動性的賣家,LSP 肯定希望理想情況下所有已經售出的流動性都不會有人回頭退款,就像每一個商家都希望的那樣。
在實踐中,如果每一單位的入賬流動性都有一個價格,而且這個價格對 A
和對 B
是一樣的,那麼來自 B
的退款就會跟來自 A
的付款完全相等。也就是說,LSP 將根本沒有動機建立這樣的機制,因為根本無法從銷售活動中賺到錢;從 A
手上獲得的支付,就會用來從 B
手上購買同等數量的流動性。
如果 LSP 給 B
支付的價格小於從 A
處收取的支付,從而可以賺取差價,那麼他就會強迫 B
結成糟糕的經濟關係。如果 B
事後又需要買回流動性,而 LSP 如法炮製,收取更高的價格,那麼 B
就在一賣一買中虧了錢。這將是一個零和遊戲,沒有人能贏到什麼。
因此,LSP 能夠實際提供入賬流動性的唯一方法,就是在專屬輸出中鎖定資金,實際上,這就是流動性的 “存貨”。
重要的是,B
將永遠不會參與使自己損失收款額度的計劃。
另一種方法是,LSP 不售賣 入賬流動性;即,不是 “LSP 售賣入賬流動性,但不向客戶收取閃電網絡路由費” 這種模式,而是 “LSP 向客戶收取非零的閃電網絡路由費,然後決定將流動性分配到何處” 這種模式。後者沒那麼理想,因為可以假設客戶總是比 LSP 更知道什麼時候自己需要流動性;舉個例子,一個商家可能有一些促銷活動,或者一個新品要上架,那就可以預期需要更多的收款額度;而且,這一消息可以在提前向 LSP 購買收款額度的活動中明顯地體現出來;這種情況下,這位客戶可以等待樹上的其他客戶上線。
激勵客戶在線
即使有一個專門的 L
輸出作為 “待售的流動性存貨”,因為 B
也需要在線,那麼一定程度上 B
也需要獲得補償。
最直接的辦法是,在參與的過程中,B
可以從 LSP 向 A
收取的流動性費用中分得一小部分。
此外,LSP 也可以直接向 B
提供一小部分的免費流動性。兩種辦法在很大程度上是等價的,因為入賬流動性也是有價值的,但這樣做的好處是,B
可以趁自己和 A
都在線,提前獲得更多流動性。稍後, A
可能會下線,讓需要入賬流動性的 B
只能使用昂貴的鏈上操作;所以,B
會更希望現在就獲得一小部分免費的入賬流動性(趁現在 A
也在線),而不是稍後再請求(那時候 A
可能離線了)。
客戶分組
一些客戶可能有規律地在一天中的某段時間地關閉電源(比如當地時間的晚上)。
LSP 可以監控客戶的在線時段,然後根據他們在 24 小時中最有可能上線的時間將他們分組。然後,在為一個新的工廠構造交易樹時,LSP 可以將 “最活躍時段” 相近的客戶分在同一個葉子以及相鄰葉子中。
這會提高一個客戶需要收款額度時,同一葉子中的其他客戶正好在線的概率;甚至,當一個葉子節點用盡了 L
專屬的資金,相鄰的葉子中的客戶也更有可能在線。
十句話,如果一個 LSP 在全球都擁有客戶,那麼按時區分組就很有利,因為相鄰時區的客戶更有可能同時在線。
樹的構造及叉數選擇
葉子節點的最佳叉數是 2,因為這意味著只需要 3 個參與者在線,就能更新一個葉子:這葉子上的兩個客戶,以及 LSP 本身。這讓狀態更新的操作更可靠。
彈出交易的叉數可以設為 1。因為一筆彈出交易的所有輸出都必須被花掉(在該彈出交易獲得區塊確認的時候),這減少了在某一客戶單方面退出時受到影響的客戶的數量。也減少了在一個葉子節點用盡 L
專屬資金時需要喚醒的客戶的數量。
不幸的是,較低的叉數意味著更大的樹高:
- 更大的樹高意味著在單方退出的情形中,需要發佈的交易更多。
- 更大的樹高意味著在單方退出的情形中,資金要經歷更長的
nSequence
相對時間鎖才能取出。- 這裡的相對時間鎖也迫使在客戶處終結的 HTLC 將自己的最終 CLTV 差值下限(BOLT11 中的
min_final_cltv_expiry_delta
)設得比曝光其通道可能要經歷的最大nSequence
時延要高,高出這個客戶認為可以 “安全” 地贖回資金的時延。因此,保證nSequqnce
較低是非常重要的,因為這個時延也決定了公開網絡上的 HTLC 將資金鎖在未決 HTLC 中、降低公開網絡容量的最長時延。
- 這裡的相對時間鎖也迫使在客戶處終結的 HTLC 將自己的最終 CLTV 差值下限(BOLT11 中的
為緩解這些問題:
- 在臨近葉子的層級中使用更小的叉數,而在更高的層級中使用更大的叉數。
- 不論如何,如果一個葉子節點無法再給一個客戶提供額外的入賬流動性,那麼 LSP 總要 “回到上一級” 並喚醒更多客戶。
- “回到上一級” 意味著需要在線的客戶數量要倍增,與節點的叉數成正比。
- 如果需要被喚醒的群體足夠大,他們全部都在線的概率就會非常低,以至於群體的規模再擴大一倍、四倍都不會有什麼影響 —— 因為他們全都在線的概率已經非常低了,低到你會老實回到鏈上,而不指望這套機制。
- 在離開葉子幾層之後,我們可以完全移除狀態交易(即帶有遞減
nSequence
的交易)。實際上,這會變成用一個根超時簽名樹輸出,來保障多個超時樹結構的 Decker-Wattenhofer 工廠,這些工廠再保障客戶的實際通道。- 同樣地,如果 LSP 必須 “回到上一級”、從葉子上溯一層到兩層狀態交易,需要被喚醒的客戶也會非常多,多到不太可能同時在線,所以,也可以通過使用更少的狀態交易層級來減少單方面退出的時延。
- 非狀態交易沒有相對時間鎖,因此在退出時不會造成額外的時延。
- LSP 可以將具有更高在線時間的客戶分在一起,將他們放在叉數更大的節點中。
- 這樣的客戶將得到更好的服務(他們會跟其他更高在線時間的客戶分在一起,因此,在他們需要入賬流動性時,同組的人更有可能在線);而且單方面退出會更便宜也更快(更高的叉數意味著更低的樹高,意味著需要發佈更少的交易)。
- 低在線時間的客戶和新客戶將獲得更多叉數為 2 和 1 的節點,因此單方面退出的代價更大,但也更好地隔絕了相鄰客戶下線的影響。
(完)