权限功能合约代码主要是:
IAuthority.sol、
Authority.sol文件, 本文从以下3个方面进行分析研究:
数据结构分析、功能模块分析、合约调用流程分析

1 数据结构分析
1.1 理想的数据机构
要想研究清楚权限合约,必须理清楚权限控制的设计思想和数据结构,这样才能真正理解合约代码这样写的背后意图。
最普通的设计思想是“控制什么人能调用合约的什么方法”,拆解成三步骤:
-
划分BSN平台上的各方角色,
-
划分合约中的函数访问权限,
-
执行合约函数时检验调用者的权限
上面的思想可以用下图表述:

使用3层Map数据结构能完美表达出上图的映射关系,最终map的值表示权限有无。
1.2 BSN的数据结构
BSN的权限合约看来看去,我终于知道了BSN的思想意图。没有使用3层map容器,把合约-函数的映射修改成了复杂的数组+映射。

优缺点:大大增加了结构复杂度和代码数量, 如果用3层map就能大大缩减代码量。
2 功能分析
2.1 角色定义、权限
用以进行对某个账户进行角色判定的逻辑实现,权限角色分为三种:运营方、
平台方、终端用户,不同角色拥有的权限各不相同,一个现实中的实体可持有多套
链账户用以对应 DDC 中的多个角色,如 BSN 可作为运营方存在于 DDC 中,三种
角色分别为下级角色的 leaderAddress,可管理该下级账户。
用户方权限:经与平台方绑定以后可进行整个 DDC 的生命周期的管理操作。
平台方权限:包含 DDC 的整个生命周期的管理以及本平台内用户方账户的增
删改查操作。
运营方权限:包含用户方账户及权限、平台方账户及权限以及运营方账户和
权限的增删改查操作,同时对 DDC 相关流转操作进行定价(DDC 发行、转移
等操作需扣除相应的费用)以及对平台方账户及用户方账户的充提操作。
enum Role {
Operator,
PlatformManager,
Consumer
}
struct AccountInfo {
// @dev The user's private key address. DDC 账户对应的 DID信息(普通用户可为空)
string accountDID;
// @dev The user's account name. 账户名称
string accountName;
// @dev The user's identity role.
Role accountRole;
/* @dev The upper-level manager of the user. This value is required only for Consumer.
* For ordinary users Consumer, this address is the associated platform manager PlatformManager.
*/
string leaderDID; //用户才有上级管理员
// @dev The current status of the account, only the platform can operate this status.
State platformState;
// @dev The current status of the account, only the operator can operate this status.
State operatorState;
// @dev Redundant field.
string field;
}
enum State {
Frozen,
Active
}
2 账户增删改查
// @dev Used to store account information for different roles.
mapping(address => AccountInfo) private _accountsInfo;
账户信息保存在 _accountsInfo 这个Map容器中,key是账户地址
功能1: 添加账户
添加运营账户 addOperator,合约owner才能调用,也就是BSN方控制着运营者账户。
平台方添加账户 addAccountByPlatform, 这个函数在手册中有,代码中被屏蔽。默认把调用者(平台方)作为上级
运营者添加账户 addAccountByOperator, 运营者添加 用户账户,
没有指定上级就是平台方,默认把调用者(运营方)作为上级。
指定上级就是普通用户方。
功能2:查询账户,检验账户
getAccount, 根据账户地址返回AccountInfo元组数据,外部函数
_getAccount, 根据账户地址返回AccountInfo结构体,内部函数
checkAvailableAndRole 检查账户是否是指定角色,账户应该存在、激活
accountAvailable 检查账户应该存在、激活
功能3: 修改账户
updateAccountState 修改账户的状态, 只有上级领导和运营者才能调用该函数,内部把调用者作为上级领导。
调用者是平台方: 修改用户的平台状态
调用者是运营方: 检查参数changePlatformState,决定修改的是平台状态、运营状态
3 授权访问合约函数
// @dev Account DID authorization collection. 平台授权
mapping(string => mapping(string => bool)) _didApprovals;
功能4: 函数授权:添加、删除 、读取 、校验权限
addFunction 运营方增加角色可调用的方法
delFunction 运营方删除角色可调用的方法
getFunctions 读取角色+合约的可调用函数数组
hasFunctionPermission : 指定账户+合约的函数校验
4 跨平台授权与检验
功能5: 跨平台授权
crossPlatformApproval 运营方通过调用该 API 进行跨平台之间的账户授权
调用者必须是运营方。
from、to两者必须都是平台方,不能相同。
map中存储的结果是 true/false, 表示有授权/无授权
onePlatformCheck 查询两个账户是否属于同平台账户。
a 都是平台角色, 两者的上级id、账户id都相同
b acc1是平台角色,acc2是用户角色: acc1是acc2的上级。
c acc1是用户角色,acc2是平台角色: acc2是acc1的上级。
d 都是用户角色, 两者的上级id相同。
crossPlatformCheck 查询两个账户是否属于不同平台账户
a 都是平台角色, 两者的上级id相同, from给to授权。 这种情况实际属于同一平台。
b from是平台角色,to是用户角色: from为to的上级授权。
c from是用户角色,to是平台角色: from为to的上级授权。
d 都是用户角色,from的上级为to的上级授权
猜测: BSN的每条链是运营方, 链上的项目方、发行方、开发方作为平台方, 消费者是用户方。
平台方控制用户的状态(激活、冻结)
运营方控制 平台方、用户的状态(激活、冻结)
3 合约调用流程分析
功能6: NFT跨平台转移,允许从一个项目平台转到其他项目平台。

调用流程:
ERC721、ERC1155合约 转账函数 transferFrom、 safeTransferFrom
---> 检查项: _isOnePlatform、_isCrossPlatformApproval
---> Authority.sol合约 onePlatformCheck、 crossPlatformCheck
功能7: 调用合约铸币、转移、授权等函数进行权限检查
在这些关键函数的第一行就检查调用者是否具备调用权限,整体流程图如下:

approve()
---> _requireSenderHasFuncPermission()
--->
_authorityProxy.hasFunctionPermission(
_msgSender(),
address(this),
msg.sig
)
---> return _funcAclList[accountInfo.accountRole][contractIdx].sigIndexList[
sig
] > 0