跳至內容
0%

什麼是 program derived address (PDA)?

發布於 2023年1月25日閱讀時間 2 分鐘

Program Derived Addresses(PDAs)是 Solana 區塊鏈上具有特殊屬性的帳戶。正確使用 PDA 可以讓 Solana dApp 開發變得快速且高效,因為它們有助於跨程式通訊。

本文將說明 PDA 是什麼、解決了哪些問題、如何運作,以及它們與Solana 帳戶模型中其他帳戶的差異。

什麼是 program derived address(pda)?

Program Derived Address 是 Solana 區塊鏈上一種沒有私鑰的帳戶。由於 PDA 不是公鑰,因此該帳戶的位址是透過程式 ID、SHA-512 雜湊函式、種子陣列(seed array)以及一個特殊的 bump seed 計算出來的。

什麼是 Solana 上的標準帳戶?

一個標準的 Solana 帳戶同時具有私鑰與公鑰(各 32 位元組),兩者共同組成一組金鑰對(keypair),長度為 64 位元組,並位於一條橢圓曲線(ED25519)上。金鑰對要有效,就必須位於此曲線上。

以下是 ED25519 橢圓曲線的示意圖:

用於 Solana 帳戶金鑰對的 ED25519 橢圓曲線圖
Solana 上的 ED25519 橢圓曲線

程式位址是如何推導出來的?

PDA 需要三個主要元件:

  1. Parent Program ID - 建立該 PDA 的父程式的 ID
  2. Seeds - 一組字串陣列
  3. Bump Seed - 確保該 PDA 不會有私鑰

要建立有效的 Program Derived Address,需要將父程式的 ID 與種子陣列一起輸入 SHA-512 雜湊函式進行運算

然而,大約有 50% 的情況下,這個雜湊結果會落在 ED25519 橢圓曲線 上,形成一組金鑰對。由於 PDA 不能有私鑰,Program Derived Address 絕不能落在橢圓曲線上。為了防止 PDA 擁有私鑰,會使用一個特殊的 bump seed,把雜湊結果「彈」出曲線之外。

Bump seed 其實只是一個數字,從 255 開始。如果即使加上 bump seed,雜湊結果仍然落在曲線上,就會再次執行雜湊函式,這次 bump 改為 254、再來是 253,依此類推,直到得出的結果不在曲線上為止。

注意:種子可以是任意字串,但開發者通常會依父程式狀態變數的特定情境來使用它們,藉此建立類似雜湊表(hashmap)的結構。

PDA 解決了哪些問題?

Program derived address 透過以程式化方式產生交易簽章,簡化了交易確認流程,讓 DeFi 帳戶等去信任化服務得以順暢運作。

以下是一個 PDA 使用情境的假設範例。

假設有一個 Solana 程式,讓使用者可以將某個 NFT 設定為預設大頭貼(PFP)。這個程式會由兩個程式組成:

  1. PFP 程式 - 建立帳戶來儲存使用者所選擇的大頭貼
  2. Core 程式 - 作為使用者輸入與 PFP 程式之間的代理

若要讓 PFP 程式更新使用者選擇的大頭貼,它需要用自己的私鑰來簽署變更大頭貼的交易。但這也代表該程式必須將私鑰儲存在鏈上。

Solana 程式無法用自己的私鑰為自己簽署交易,因為該金鑰本身會儲存在鏈上,所有人都看得到。若真是如此,該私鑰就可能被用來代表該程式簽署交易,進而更改任何使用者的大頭貼。

試想,如果這個 PFP 程式管理著數百萬顆 SOL token,這樣的漏洞將會演變成一場重大的駭客事件。Program Derived Address 正是為了解決這個問題而存在。

為什麼 PDA 很重要?

Program Derived Address 在 Solana 程式設計中扮演關鍵角色,因為它們有助於不同程式之間的通訊(Cross Program Invocation),也可以作為雜湊表,用來儲存父程式能輕鬆更新與變更的特定資料。

1. 儲存程式的狀態變數

PDA 讓 Solana 開發者能夠儲存並追蹤與特定使用者相關的變數或一組變數。PDA 最典型的用途,就是為其父程式儲存狀態變數或資料,因為它預設就已授權父程式代表它進行變更。

2. 將 PDA 當作雜湊表使用

Mapping 代表一組鍵值對(key-value pairs),用來透過鍵快速找到相關聯的資訊。在 Solana 開發中,透過 PDA 的種子與正確的字串,也能達成同樣的效果。

讓我們回到前面提到的錢包大頭貼範例。

當使用者選定他們錢包的 PFP 後,PFP 程式會拿選定的圖片與使用者的位址,將這兩者作為「種子」來建立一個 PDA,用來儲存使用者的選擇。

一旦雜湊演算法成功找到這個 Program Derived Address,其公鑰就會「對應」到使用者的位址與所選的 NFT 頭像。

如果再多提供一個 PDA 作為第三個種子,這個雜湊表功能還能發揮得更好。我們可以將所有可選的大頭貼收集起來,儲存在另一個獨立的 PDA 中,並把每一張大頭貼作為它的種子,最終得到一個儲存所有大頭貼的 PDA。

這樣一來,當使用者來選擇他們的大頭貼時,這個 PDA 看起來就會像一個雜湊表,因為透過這些種子,你可以看出:從一組大頭貼選項(PFP 群組 PDA)中,某個作為第一個種子傳入的使用者位址,選擇了作為第二個種子傳入的那張大頭貼。

這個範例可以進一步延伸,建構出更深層的雜湊表結構。

PDA 作為 hashmap 的程式流程 - NFT 範例
PDA 作為 hashmap 的程式流程 - NFT 範例

3. 跨程式呼叫(Cross program invocations)

Cross Program Invocation(CPI)是指一個程式呼叫另一個程式中函式的過程。CPI 之所以有用,是因為它們讓程式碼有更好的組合性(composability)。

回到我們的範例,假設某位使用者想把他的大頭貼從 Degen Ape 換成 Solana Monkey Business 頭像。

以下是背後實際發生的流程:

當使用者登入錢包時,core 合約會取得使用者的位址(公鑰),並尋找一個已經建立、種子中包含該使用者公鑰的 PDA。

找到之後,core 程式會呼叫 PFP 程式中一個名為「changePFP()」的函式(這就是一次 Cross-Program Invocation),並將 core 程式已經「選定」的那個 PDA 作為參數傳入。

一旦這個函式被呼叫,被選定的 PDA 會檢查「要求」進行變更的帳戶是否為其父程式。如果 PDA 不相符,交易就會被拒絕,因為只有父程式才能修改該 PDA 的資料。

由於 PFP 程式是這個被選定的 PDA 的父程式,因此它有權將使用者選定的大頭貼從 Degen Ape 改為 SMB 頭像。

使用 PDA 進行跨程式呼叫 - 變更 NFT 圖片
使用 PDA 進行跨程式呼叫 - 變更 NFT 圖片

Program Derived Address 讓其父程式能夠代表它進行簽署,並可用於儲存程式的狀態、建立雜湊表,以及進行跨程式呼叫。PDA 是 Solana 程式設計領域中的基礎主題,能讓 dApp 開發變得快速且高效。

Program derived address 常見問題

在處理 Program Derived Address 時,了解 Solana 如何處理交易與資料會很有幫助。帳戶主要有兩種類型:可執行(executable)與不可執行(non-executable)。

什麼是可執行帳戶?

可執行帳戶,也稱為 程式(programs),類似於 Ethereum 的智能合約——一段程式碼,當某個帳戶與它互動時,會改變其狀態。

什麼是不可執行帳戶?

不可執行的資料帳戶單純用來儲存資料(例如帳戶擁有的 SOL 數量、NFT、token 餘額等),基本上就是程式的狀態變數。

Solana 程式的資料儲存方式與 Ethereum 智能合約有何不同?

Ethereum 與 Solana 之間一個根本性的差異,在於可執行程式碼的儲存方式。Ethereum 上的智能合約本身就「內建」了儲存所有狀態變數的 storage。相較之下,Solana 上的程式並沒有內建的 storage,而是擁有各自獨立的資料帳戶,用來持有並參照它們想要儲存的各種狀態變數。

Background gradient

打造區塊鏈魔法

Alchemy 結合最強大的 Web3 開發者產品與工具,並提供資源、社群與卓越的支援。