• BSN-DDC 合约研究01---权限合约


    权限功能合约代码主要是: IAuthority.sol、 Authority.sol文件, 本文从以下3个方面进行分析研究:
    数据结构分析、功能模块分析、合约调用流程分析
    1 数据结构分析
    1.1 理想的数据机构
    要想研究清楚权限合约,必须理清楚权限控制的设计思想和数据结构,这样才能真正理解合约代码这样写的背后意图。
    最普通的设计思想是“控制什么人能调用合约的什么方法”,拆解成三步骤:
    1. 划分BSN平台上的各方角色,
    2. 划分合约中的函数访问权限,
    3. 执行合约函数时检验调用者的权限
    上面的思想可以用下图表述:
    使用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
                        

  • 相关阅读:
    Java顺序表和链表
    TypeScript又出新关键字了?
    C/C++内存管理
    “三门问题”解决方案:换不换?更换策略与贝叶斯策略?附 Java 验证代码
    一份企业业务流程自动化指南
    CG-34 浊度传感器 简单说明
    Attention机制学习记录(四)之Transformer
    老生常谈!程序员为什么要阅读源代码?
    Docker通信全视角:原理、实践与技术洞察
    uniapp 使用和引入 thorui
  • 原文地址:https://blog.csdn.net/u012084827/article/details/127119625