在Aragon中,一個DAO由三個內部Dapp和多個外部Dapp(用來拓展功能)共同組成,這其中外部Dapp又包括代幣、投票、資金這幾個核心功能。Dapp之間交互必然會涉及到權限管理,因此這篇文章簡要分析了Aragon DAO中的權限結構設計,爲我們開發自己的DAO提供一些參考或借鑑。 |
一、權限的分類
在Aragon DAO中,權限分爲兩類。一類是角色權限,是指某Dapp中特定功能的執行權限;另一類是管理權限,是指對Dapp中角色權限的管理。
這裏舉一個例子來說明:
假定有合約A 、 B 、C 、D 。合約A有一個寫數據的方法f,用來更改合約A中的狀態變量X,如下:
- 調用 A.f() 的來更改X的權限,假定爲B,這就是角色權限。
- 更改a.f()的調用權限爲C(這時不是更改X) ,這是由D來負責的,這就是管理權限。
這裏不管是角色權限還是管理權限,都可以設定爲DAO中任意Dapp(包括內部和外部)、指定地址或者任意賬號。
在Aragon Dao中,點擊權限欄目,可以看到外部Dapp默認管理權限都是投票合約,也就是所有管理活動都必須投票通過才行,這符合DAO的本意。如下圖:
二、權限的實現
不管是角色權限還是管理權限,都是使用map來存儲,具體實現在ACL.sol中的ACL合約中。
2.1 下面的map
記錄了Dapp的角色權限
mapping (bytes32 => bytes32) internal permissions; // permissions hash => params hash
它的鍵是一個bytes32,代表角色的哈希值,對應的也值爲一個哈希,是權限參數數組編碼後得到的。
角色哈希值是這樣計算的:
function roleHash(address _where, bytes32 _what) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("ROLE", _where, _what));
}
這其中_where
代表Dapp地址,_what
代表進行的具體操作。比如代幣Dapp的增發功能,這裏_where
就是代幣的地址 _what
是一個代表增發操作的bytes32
。
2.2 下面的map記錄了上面得到的參數哈希對應的參數數組
mapping (bytes32 => Param[]) internal permissionParams; // params hash => params
2.3 下面的map記錄了Dapp的管理權限
mapping (bytes32 => address) internal permissionManager;
它的鍵是一個bytes32
,代表管理權限的哈希值,對應的值爲一個地址,用來代表權限擁有者的地址。
管理權限的哈希計算在這裏就不再列出。
三、權限初始化
我們直接從ACL合約的初始化函數開始,代碼如下:
/**
* @dev Initialize can only be called once. It saves the block number in which it was initialized.
* @notice Initialize an ACL instance and set `_permissionsCreator` as the entity that can create other permissions
* @param _permissionsCreator Entity that will be given permission over createPermission
*/
function initialize(address _permissionsCreator) public onlyInit {
initialized();
require(msg.sender == address(kernel()), ERROR_AUTH_INIT_KERNEL);
_createPermission(_permissionsCreator, this, CREATE_PERMISSIONS_ROLE, _permissionsCreator);
}
onlyInit
是限定只初始化一次的函數修飾符。
函數體裏第一行是初始化,比如存儲當前blockNumber
等。
第二行是檢查調用權限,只能爲核心合約(kernel合約)。
最後一行創建了ACL合約的初始權限,我們來看這個內部函數的定義:
/**
* @dev Internal createPermission for access inside the kernel (on instantiation)
*/
function _createPermission(address _entity, address _app, bytes32 _role, address _manager) internal {
_setPermission(_entity, _app, _role, EMPTY_PARAM_HASH);
_setPermissionManager(_manager, _app, _role);
}
結合這兩個函數,我們可以看到權限初始化做了兩件事(略過相關代碼展示):
- 設置本合約(ACL)的角色權限爲
_permissionsCreator
- 設定本合約(ACL)的管理權限爲
_permissionsCreator
四、權限管理
合約中管理權限的函數有:
createPermission
用來未設置過管理權限時進行設置,也可用於移除管理權限後再設置。grantPermission
和grantPermissionP
更換某個Dapp的角色權限,分別對應未設置過管理權限和設置過管理權限後。revokePermission
取消某個Dapp的角色權限,需要管理權限。setPermissionManager
更換某個Dapp的管理權限,需要管理權限。removePermissionManager
移除某個Dapp的管理權限,需要管理權限。createBurnedPermission
和burnPermissionManager
移除某個Dapp中不存在的角色功能,分別對應未設置過管理權限和設置後。
下面的方法爲權限查詢函數:
getPermissionParamsLength
用來獲取權限參數數組的長度getPermissionParam
用來獲取特定索引的權限參數getPermissionManager
返回某個Dapp的管理權限hasPermission
返回調用者是否有某個Dapp的某些角色權限
ACL合約中其它方法都是不對外的內部輔助方法,不再介紹。
好了,對 Aragon DAO 權限的簡單分析就到這了。本文主要是做了一個大致介紹,如果想要進一步深入細節,需要查閱相關合約的源代碼實現。
歡迎大家留言指出錯誤或者提出改進意見。
2019年最後一篇文章!!!