智能合約開發

鑽石模式

鑽石模式是一種代理,它委派的對象不是一個實作而是許多個。想像一個中央樞紐——鑽石——被一圈可互換的切面(facet)環繞,每個切面是一個獨立合約,提供系統的一部分函數。樞紐查出每個進來的函數屬於哪個切面,並 delegatecall 它。對呼叫者而言,它呈現為一個帶有單一龐大、統一介面的位址。

機制上(EIP-2535),鑽石儲存一個從每個 4 位元組函數選擇器到實作它的切面位址的映射。它的 fallback 讀取選擇器、找到對應的切面,並 DELEGATECALL 進去,於是切面的程式碼針對鑽石的共享儲存執行。一個標準函數 diamondCut 用來新增、取代或移除選擇器到切面的映射,並發出一個標準事件,透過「放大鏡」(loupe)函數讓完整介面保持可內省。最醒目的好處是把程式碼分散到你想要的任意多個切面上,從而繞過 24,576 位元組的 EIP-170 合約大小上限。

代價是貨真價實的複雜度。由於所有切面共享同一個儲存空間,你必須以高度紀律管理佈局——Diamond Storage 與 AppStorage 慣例把每個模組的變數放在一個固定、有命名空間的結構體槽位,以避免碰撞,因為天真的共享佈局會讓一個切面踩壞另一個的狀態。這層額外的間接與儲存紀律,使鑽石比單一實作更難推理與審計,所以它們主要在非常大型、模組化的系統(龐雜的遊戲或協議)上才划算,而非一般合約——在後者中,透明代理或 UUPS 更簡單也更安全。

// diamond fallback, conceptually:
address facet = selectorToFacet[msg.sig];
require(facet != address(0), "function not found");
// delegatecall into facet against the diamond's storage

一個位址、多個切面、一份共享儲存。

鑽石以共享儲存為代價換取無上限的程式碼大小。難處不在路由——而在有紀律、有命名空間的儲存佈局,使切面永不碰撞。