使用 Substrate 的賬戶抽象,開發者可以構建一個可擴展性和安全性更高的錢包解決方案。

原文標題:《怎樣使用 Substrate 做一個能安全支持百萬地址的熱錢包?》
撰文:Joe Petrowski
翻譯:PolkaWorld 社區

用於 runtime 開發的 Substrate 和 FRAME 系統定義了一組強大的原語功能,用於構建區塊鏈基礎架構。將兩者共同使用,爲解決現有問題創造了新穎的方法。本文將描述一個實際應用程序,其中 Substrate 的函數用於實現多地址熱錢包。

波卡生態開發者請進:如何用 Substrate 實現多地址熱錢包?

熱錢包通常意味着將支出密鑰保存在在線設備上,以便可以方便地創建和廣播交易,但風險通常較高。本文將探討一些 Substrate 的賬戶抽象 —— 多簽名賬戶、代理賬戶和衍生賬戶 —— 如何讓我們能構建一個可以安全支持數百萬個地址的熱錢包。

如果您需要爲多個用戶賬戶持有代幣,但又想爲每個客戶提供自己的存款地址,那麼這樣的錢包將非常有用。簡單的解決方案是通過生成新的密鑰對爲每個客戶生成一個新的存款地址。但是快速處理所有這些密鑰對並不容易。如果您有成千上萬的用戶怎麼辦?使用 Substrate 的賬戶抽象,我們可以構建一個可擴展性和安全性更高的解決方案。

來源和賬戶 ID

在開始構建熱錢包之前,我們需要奠定它將要使用的基礎。當用戶與區塊鏈進行交互時,他們正在調用某些函數。這些 「可調度(dispatchable)」 函數的集合構成了區塊鏈的界面。

由於可調度函數是從外部調用的,因此區塊鏈可能首先關心的是誰真正調用了該函數。首先,一個函數需要檢查調用方是否有權執行該函數。其次,鏈可能需要確切地知道誰調用了該函數以更新有關調用者的一些信息。如果調用者是一個賬戶,則鏈可能需要更新該賬戶的餘額,例如扣除交易費用。

您可能會想,「如果調用者是賬戶,那意味着什麼?」 Substrate 中的函數本身不是來自帳戶,而是來自來源(origins)。例如,Polkadot 的治理系統具有一系列特殊來源,這些特殊來源具有特權,例如分配國庫資金或撤銷 Slash。如果您使用 Substrate 設計自己的區塊鏈,則可以創建自己的自定義來源。但是,本文要記住的一點是,賬戶只是 Substrate 來源的一種變體。您可以想象成 Substrate 告訴可調度函數,「此調度的來源是一個賬戶。」

既然我們已經實現了抽象的第一個飛躍,我們需要一種方法來告訴函數來源是指哪個賬戶。如果您使用過任何區塊鏈,則可能會習慣於使用一個賬戶 ID 作爲與私鑰相對應的公鑰。這沒問題,這一點也可以在 Substrate 中使用。從這個意義上說,一個賬戶由公鑰標識,並由相應的私鑰授權。

Substrate 支持更多抽象。賬戶 ID 可以是任何 32 個字節的數字。[1] 可以是與私鑰相對應的公鑰,但不是必須的。它只需要某種授權方法。就像在其中一樣,必須有某種獨特的方法來生成此帳戶標識號,以便 Substrate 可以完成上述開頭的句子:「此調度的來源是由該編號標識的賬戶。」 [2]

哈希函數

哈希函數一直在區塊鏈中出現。區塊實際上是通過其哈希值鏈接在一起的。但是我們將使用哈希函數的屬性來達到另外兩個目的:生成賬戶 ID 和識別函數調用。

哈希函數會接受一些任意大小的輸入,並將其映射到固定大小的輸出(例如 32 個字節)。但是,它不僅將數據映射到任何 32 字節的數字,而是應該確定性地將唯一數據映射到一個唯一的數字。碰巧的是,32 個字節可以捕獲天文數字量級的 item。[3]

例如,我們可以獲取有關鏈的一些信息,例如 「polkadot-treasury」,並使用哈希函數將其轉換爲賬戶 ID (32 字節)。或者,我們可以獲取有關某些交易的信息,例如 「將 10 個單位轉移到賬戶 123…」,並相信哈希是該信息的唯一圖像。

多籤賬戶

有了這些,我們就可以開始構建熱錢包的第一部分:多重簽名(multisig)賬戶。由於總體比較笨重,多重簽名賬戶可能看起來不像是熱門錢包的一部分,但是此賬戶將作爲其餘組件的安全基礎,並且剛剛所說的笨重不會妨礙日常使用。

一些區塊鏈使用加密多重簽名,其中多個密鑰持有者在鏈上提交交易之前,先在鏈外簽署了單個交易。Substrate 的 FRAME 附帶的多重簽名系統以另一種方式工作:它根據構成多重簽名的各個賬戶以及從生成的賬戶中分發所需的必要閾值來生成賬戶 ID。Substrate 向所有這些信息添加一個特殊的多重簽名前綴,並對其進行哈希處理以獲取一個 32 字節的輸出,該輸出將用作多重簽名賬戶 ID。請注意,此賬戶 ID 沒有與其關聯的私鑰。

爲了從該新帳戶 ID 授權交易,多籤的成員均使用其希望多簽帳戶進行的函數調用在鏈上提交交易。但是,每個人都提交函數調用效率不高;它可能很大,並且區塊空間是稀缺的(因此很昂貴)。哈希函數再次派上用場:只有一個賬戶需要提交實際的函數調用;其他人只提交哈希。他們只用說:「我們同意通過多籤賬戶使用此哈希調用函數」,而無需重新提交函數。

這個多重簽名本身太笨拙,無法用作熱錢包,因爲它需要多個密鑰持有者提交交易才能使其正常工作。但是它是高度安全的,可以將它作爲基本賬戶,而我們可以在不犧牲其安全性的情況下將其轉變爲熱錢包。

代理賬戶

代理帳戶允許多籤地址將支出權限委派給另一個賬戶,該賬戶將用作熱錢包,同時仍保持多籤的安全。我們將設置一次性延時代理來管理支出,並設置另一個(或多個)即時代理來管理此多籤賬戶的安全性。

代理賬戶將一個賬戶的特權授予另一個賬戶,以代表該賬戶進行函數調用。這些特權可以是特定的,例如 「僅限與抵押相關的交易」,或廣泛的,例如 「不涉及轉移資金的所有交易」,甚至是完整的特權,如 「任何交易」。

創建代理只需要從要代理的賬戶進行一次交易,並說明哪個其他賬戶是其代理及其特權。代理關係到位後,代理賬戶就可以爲代理賬戶進行交易,本質上就是告訴鏈:「我是該賬戶的代理,我具有這些特權,並且我想代表代理賬戶。」 鏈的邏輯將驗證代理確實具有正確的特權,並使用代理賬戶的來源派遣該功能。

添加時間延遲會增加一層安全性。想象一下 600 個區塊的時間延遲(在 Polkadot 中爲一小時)。代理賬戶仍會提交交易,說它是具有某些特權的代理,但只會宣佈它要進行的函數調用的哈希值。代理賬戶的所有者可以請求實際的函數調用並進行審查。如果所有者不同意,他們可以通過在延遲時間到期之前提交另一個交易來拒絕函數調用。在時間延遲之後,代理可以提交與公告相對應的實際函數調用,然後由 Substrate 調度。[4]

對於我們的用例,多籤密鑰持有者將進行交易以將另一個賬戶設置爲具有完全特權的延時代理,例如包括餘額轉移在內。也許此代理賬戶將存在於可自動進行交易的在線服務器上。每當進行交易時,它都必須先宣佈哈希,然後將實際的函數調用發送給其他帳戶持有人(爲簡單起見,我們將此其他帳戶持有人視爲多籤的成員),他們可以驗證該函數調用是否爲非惡意的。如果是惡意的,多籤可以及時進行交易以拒絕該調用,並且出於謹慎考慮,確定代理賬戶已被盜用並將其刪除。

這樣配置確實行得通,但是我們仍然可以讓它變得更方便使用。僅使用一個代理,我們可能需要很長的時間延遲,因爲協調足夠多的多重簽名密鑰持有人以進行拒絕交易可能會在短時間內比較困難。但是一個帳戶可以有多個具有不同特權的代理帳戶。要解決此問題,請將每個多籤密鑰持有者設置爲具有非轉賬特權的代理,尤其是具有拒絕來自延時代理的通知的特權。

讓我們簡要介紹一下此配置。在中心,我們有一個多籤賬戶。該賬戶沒有私鑰,但是有兩種方法可以控制它:使用延時代理賬戶或收集足夠的成員賬戶簽名者。多籤的每個成員還具有拒絕來自完全特權代理的交易的能力,但是如果沒有其他成員加入進行多籤交易,則無法進行餘額轉賬。

它自己就是一個功能齊全的熱錢包,只需刪除代理並設置一個新的熱錢包即可更改熱鍵(具有完全特權的代理帳戶),而無需更改其地址(多重簽名帳戶)。但是我們最初的問題陳述要求成千上萬的用戶使用唯一的存款地址,到目前爲止,我們只有一個用戶。

衍生賬戶

到目前爲止,我們已經使用多種方式訪問一個多重簽名賬戶。現在,我們將使用一個帳戶訪問許多賬戶。

Substrate 中的每個賬戶都有一個可以訪問的衍生帳戶樹。爲了獲得賬戶 ID,Substrate 理所當然地使用來哈希算法。通過用所需的索引和派生前綴對發起調用的帳戶的賬戶 ID 進行哈希處理,Substrate 創建了一個新的賬戶 ID。例如,發送方提供一個函數調用和一個索引,說:「我想從具有此索引的派生賬戶中調度此函數。」

你可能已經猜到後面會發生什麼了。錢包所有者可以爲其每個用戶分配一個索引,並提供派生賬戶 ID 作爲該用戶的存款地址。爲了訪問資金,代理地址將發出交易以從多重簽名帳戶的派生地址轉移資金。

具體而言,索引限制爲 16 位或 65,536 個派生帳戶,但是也可以嵌套。也就是說,每個衍生產帳戶可以擁有自己的 65,536 個衍生產帳戶集,依此類推。樹的第二層將擁有超過 40 億個賬戶。

全貌

最後讓我們把這些知識用起來。想象一下,索引爲 11 的用戶向您付款,您有一些 「儲蓄賬戶」 要存入資金。整個交易看起來像是:「我是多籤賬戶的代理人,我想將資金從多籤的衍生賬戶(索引爲 11) 轉移到儲蓄賬戶。」

假設對監管者來說一切正常,則延遲時間將到期,並且代理可以廣播完整的交易。如果多重簽名成員認爲熱鍵需要更改,他們可以簡單地生成一個新密鑰並將舊密鑰作爲代理刪除,而不會影響多重簽名或其任何派生地址。

波卡生態開發者請進:如何用 Substrate 實現多地址熱錢包?

上圖顯示了我們已設置的錢包的示意圖:多重簽名(MS)由一組 n 個密鑰(記爲 k)控制,並將時間延遲代理(H)設置爲熱鍵。它幾乎可以從多籤中導出無限的地址(d 的集合)。

我們甚至可以進一步優化此工作流程。Substrate 還提供了發送一批函數調用的函數。如果用戶定期在其衍生帳戶中進行存款和提款,你可以在一批轉賬中將其全部發送。

Substrate 的鏈上帳戶抽象提供了管理賬戶的強大方法。通過減少所需的實際密鑰數量並根據正式規則而不是私鑰訪問賬戶,您可以操作成千上萬個賬戶,而不必處理存儲相等數量的簽名密鑰的限制。本文僅關注構建熱錢包的一個示例,但是所有抽象都是孤立的,可以組成更高級的應用程序。

註釋

1. 不必非得是 32 個字節。您可以隨心所欲地構建 runtime,但我不希望本文超出了必要範圍。

2. 快速解釋一下 「unique」 一詞,從嚴格的意義上講,我在這裏的意思比普通字典中的定義更嚴格。一個賬戶是唯一的,並不是說它只能有一個表示,而是所有表示(或一系列表示)都可證明爲相等的。可能存在無限數量的方法來生成一個特定的數字(賬戶),但是隻要所有這些方法都確實生成相同的帳戶,那麼該賬戶就可以視爲唯一的。詳細解釋其中的數學原理會複雜到讓你頭大,但是我們將生成賬戶 ID 並將它們在函數之間傳遞,這裏的關鍵是無論我們有多少個函數串在一起(串聯)以到達某個帳戶 ID,它在充當調度源的方面表現爲相同的賬戶 ID。

3. 如果您有興趣瞭解的話,32 個字節最多可容納 1.15x10 ^ 77。到可觀察宇宙邊緣的距離爲 457 億光年,即 4.32x10 ^ 23 公里或 4.32x10 ^ 29 毫米。如果我們我們把它想作是一張平面的光盤,則其面積爲 5.87x10 ^ 59 平方毫米。我們仍然相差 10 ^ 18 或十億平方。因此,兩個不同的哈希輸入具有相同輸出的機會就像兩個項目都落在可觀察的宇宙中的同一平方毫米上,然後將其分解爲 10 億乘以 10 億的網格,然後又都落在了相同的正方形上。這些正方形是 1 皮米(picometer)寬。作爲參考,氦原子的直徑爲 62 皮米。

4. 實際上,只要代理髮出通知,任何賬戶都可以提交調用,但是出於實用主義的考慮,假設我們的熱錢包僅使用同一賬戶進行通知和提交。

來源鏈接:www.parity.io