
0. 回顧
1. 概述
在前一篇部落格中,我們介紹了如何透過 invoke 和 invoke_signed 函數來實現跨程序調用。在這篇文章中,我們將介紹另一個基礎主題——程序升級(Program Upgrade)。
2. 部署可升級程序
預設情況下,所有部署的程序都使用 Solana 中的 BPFLoaderUpgradeable 載入器,這意味著它們是可以升級的。除此之外,Solana 還提供了 --final 選項,以確保部署的程序是不可變的。在這種情況下,系統將使用 BPFLoader2 載入器來部署程序。一旦部署完成,該程序即無法升級。
BPFLoaderUpgradeable 載入程序管理三種類型的帳戶:程序帳戶(program accounts)、程序數據帳戶(program data accounts) 以及 緩衝區帳戶(buffer accounts)。在部署過程中,系統會先建立一個緩衝區帳戶。隨後,Solana CLI 會載入目標程序的位元組碼(bytecodes)並將其寫入緩衝區帳戶中。最終,儲存在緩衝區帳戶中的位元組碼會被複製到程序數據帳戶中。
因此,緩衝區帳戶由可升級 BPF 載入器用於在部署過程中暫存位元組碼;程序數據帳戶儲存程序的實際數據;而程序帳戶則作為指向對應程序數據帳戶的代理。
接下來,讓我們通過幾個範例來了解如何升級你的程序。本文中使用的所有程式碼都可以在這裡找到。
2.1 程式碼回顧 (Rectangle_Area)

在這個範例合約中,我們定義了一個名為 Rectangle 的結構體,其中包含了 width、height 和 area 三個屬性(第 13 行至第 17 行)。我們也為 Rectangle 定義了一個 area() 函數,該函數用於利用 width 和 height 計算矩形的面積。

在 process_instruction() 函數中,我們首先使用 unpack_u32() 函數從指令數據中提取矩形的 width 和 height(第 45 行至第 46 行)。在第 51 行,提取了用於儲存矩形數據的帳戶。在第 59 行,try_from_slice_unchecked() 函數將帳戶數據反序列化為 Rectangle 結構體類型。接下來,我們將數據賦值給結構體的對應欄位並計算面積值(第 61 行至第 63 行)。最後一步是序列化數據,並將其寫回數據帳戶。
部署後的程序可以在以下連結中找到。
https://explorer.solana.com/address/84mMqHRTQT6b2vfsD7XRxVKA3XMd7xoEXFdF6pLNw8y?cluster=testnet
2.2 發送交易

在客戶端,我們首先發送一個交易來建立一個用於儲存數據的帳戶。我們將空間大小設置為 1,024 位元組以確保足夠使用。

然後,我們發送另一個交易來計算矩形的面積,並將結果儲存到數據帳戶中。
該交易可以在以下連結中找到。
https://explorer.solana.com/tx/4PybjXGRpuPKpak7FAz4BKMbcQCWmway69zAxtTnpFRuTTg7onyxW7agSe6ETx44iAGexbgnBUa8WdzdTTQSawJ3?cluster=testnet
3. 升級
現在,我們想要在程序中添加一個新功能,即計算矩形的周長。

編譯更新後的專案後,我們使用以下命令升級鏈上的部署程序。
solana program deploy /path/to/program.so --program-id <PROGRAM_ID>
合約可以直接升級,您可以查看下方的相關交易。
https://explorer.solana.com/tx/4Dm9v4zMiijKjQBhatx1D9xbV9PvMLdaonUWLaC2VwzkFvzdgorzbX5vsy4VQ7VxSUmqadftjiDzbyUmXgQchYmk?cluster=testnet
我們隨後向程序發送一筆交易,以驗證其是否升級成功。結果顯示該功能運作正常。
相關交易可以在下方找到。
https://explorer.solana.com/tx/21c2G7kPVktAtdUFkH3QwGVi7orajRmy5PJo1UxX1mmAMU68eUkNuLzWYJRBaTzwGi5DxeocYjHfpWiU4hcSFtpQ?cluster=testnet
4. 再次升級

這次我們想將計算出的周長儲存到數據帳戶中。為此,我們在 Rectangle 結構體中多增加了一個屬性 perimeter(第 18 行)。

由於數據帳戶的結構與之前不同,我們需要先從數據帳戶讀取數據。我們使用原始結構體(即 OldRectangle)反序列化儲存的數據。之後,我們將相關屬性賦值給新的結構體(即 CurrentRectangle)並初始化新屬性(即 perimeter)。

最後,我們計算周長值,並將其賦值回 update_account,然後將其序列化到 account_data 中。
升級交易可以在下方找到。
https://explorer.solana.com/tx/5J3oKxZXtCi755gD7pMnVh48AFvmeVzRLPgJiyNn8JFeCKx1xpAfJtsi34zjyYKJmnMk8LtC3bcwfFSP7H2gtj5o?cluster=testnet
升級完成後,我們可以使用 solana account <DataAccount> 命令檢查儲存在帳戶中的數據。您可以發現這些屬性儲存在前 32 個位元組中。至此,整個升級過程結束。

5. 總結
在本文中,我們介紹了 Solana 中的程序如何升級。我們透過不同的範例說明了詳細的過程。請持續關注,後續我們將發布更多關於 Solana 的文章。
閱讀本系列的其他文章:
- 保護 Solana 生態系統 (1) — Hello Solana
- 保護 Solana 生態系統 (2) — 程序間呼叫
- 保護 Solana 生態系統 (4) — 帳戶驗證
- 保護 Solana 生態系統 (5) — 多重簽名
- 保護 Solana 生態系統 (6) — 多重簽名 2
- 保護 Solana 生態系統 (7) — 類型混淆
關於 BlockSec
BlockSec 是一家開拓性的區塊鏈安全公司,由一群全球傑出的安全專家於 2021 年成立。公司致力於提升新興 Web3 世界的安全性和可用性,以促進其大規模採用。為此,BlockSec 提供智慧合約與 EVM 鏈的安全審計服務,開發了用於安全開發與主動阻斷威脅的 Phalcon 平台,用於資金追蹤與調查的 MetaSleuth 平台,以及協助 Web3 建設者在加密世界中高效航行的 MetaSuites 擴展插件。
截至目前,公司已為 MetaMask、Uniswap Foundation、Compound、Forta 和 PancakeSwap 等超過 300 家知名客戶提供服務,並在兩輪融資中獲得了包括矩陣夥伴(Matrix Partners)、Vitalbridge Capital 和分佈式資本(Fenbushi Capital)在內的頂尖投資機構數千萬美元的融資。
官方 Twitter 帳號:https://twitter.com/BlockSecTeam



