github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/permission/contract/Permission.sol (about)

     1  pragma solidity >=0.4.22 <0.7.0;
     2  //约定命名下横线的方法为内部方法
     3  //nodeId格式为:
     4  //enode://98d1fb92def94a3b8a861c7b1837aa9364126f5f12368db9194f0e152490277da8d5351a3e4796c10faf6c6af16a2185b5cb0a119d05111864eb284875f0bbe9
     5  //加入网络:0;剔除网络:1;升级:2;降级:3
     6  /**
     7   * @title Permission
     8   */
     9  contract Permission {
    10      //联盟创始节点不允许退出联盟
    11      //联盟创始节点
    12      uint private constant originator=2;
    13      //管理节点
    14      uint  private constant admin=2;
    15      //普通节点
    16      uint  private constant common=0;
    17      //游离节点
    18      uint  private constant isolated=1;
    19      // 0 加入联盟
    20      string  private constant opJoin="0";
    21      // 1 退出联盟
    22      string  private constant opExit="1";
    23      // 2 升级为管理节点
    24      string  private constant opAdmin="2";
    25      // 3 降级成普通节点
    26      string  private constant opCommon="3";
    27  
    28      // events related
    29      event AddNewNodeNotify(string enodeId, string ip, string port);
    30  
    31      event VerifyNotify(string enodeId,uint opCode,string ip, string port);
    32  
    33      event ApplyByAdminNotify(string enodeId);
    34  
    35      event networkInitComplete(uint number,uint timestamp);
    36  
    37      event isVotedEvent(string  _nodeId,string  _opCode, string  _voterNodeId);
    38  
    39      event isAdminRoleEvent(string _nodeId,address _sender);
    40  
    41      //控制网络初始化的变量,就是整个网络有个初始化的过程,初始化完成之前,admin的节点是随便添加的
    42      //初始化完成之后,添加节点都是需要经过投票的。
    43      bool  private  networkStatus = false;
    44  
    45      //管理员的数量
    46      uint private adminCount; //administrator count
    47  
    48      struct Node {
    49          string nodeId;//节点id
    50          string ip;//节点ip地址
    51          string port;//节点端口
    52          string nodeName;//节点名称
    53          address nodeAddress; //节点账号地址
    54          bool isOriginator;  //是否创始人,联盟创世参与者,创世参与者不允许退出联盟
    55          // 0 表示普通节点
    56          // 1 表示游离节点
    57          // 2 表示管理节点
    58          uint role;
    59          uint createdAt ;
    60          //表示的是纳入管理,就是说要投票加入了,那么就为true,退出网络就为false
    61          bool exist ; //存在性标志,添加时设置为true,退出网络时设置为false,这样就可以反复利用
    62      }
    63      //Used to count votes--统计投票数据
    64      struct Statistics {
    65          bool exist ; //存在性标志
    66          //节点
    67          string nodeId;
    68          //同意票数
    69          uint agree;
    70          //不同意票数
    71          uint disagree;
    72          //发起提案的节点
    73          string proposeNodeId;
    74          // 0 加入联盟
    75          // 1 退出联盟
    76          // 2 升级为管理节点
    77          // 3 降级成普通节点
    78          string opCode;
    79          //投票完成状态,
    80          // 0:未完成;
    81          // 1:已完成
    82          uint status;
    83      }
    84      //投票记录
    85      struct VoteRecord {
    86          //投票对象
    87          string nodeId;
    88          //投票人
    89          string voterNodeId;
    90          //投票人地址
    91          address voterAddress;
    92          //投票针对的操作
    93          string opCode;
    94          //投同意票,还是投反对票
    95          //赞成:true,反对:false
    96          bool auth;
    97      }
    98  
    99      //节点都在nodeMap 中(包括游离节点、普通节点、管理节点)
   100      //在网络中或曾加入网络的节点信息,key:hash(nodeId)
   101      mapping(bytes32 => Node)  private nodeMap;
   102  
   103      //存在的节点
   104      mapping(bytes32 => bool)  private existNodeIds;
   105  
   106      //用来保存节点的id
   107      bytes[] private nodeIds;//store nodeId
   108  
   109      address[] private originators;
   110  
   111      //统计票数的记录,key:hash(nodeId+opCode)
   112      mapping(bytes32 => Statistics)  private statisticsMap;
   113  
   114      //投票记录
   115      VoteRecord[] private voteRecords;
   116  
   117      //对于每一次投票,记录投过票的管理员节点,key:hash(nodeId+opCode)
   118      //string[] 投票者集合
   119      mapping(bytes32 => string[]) private voterMap;
   120  
   121      modifier checkNetworkStatus() {
   122          require(!networkStatus, "can not set admin node,initialize finished.");
   123          _;
   124      }
   125      modifier checkInitStatus() {
   126          require(networkStatus, "can not invoke method except setAdmin function,initialize have not finished.");
   127          _;
   128      }
   129      //节点移除、节点升级、节点降级
   130      //都走这个方法
   131      // opCode 3为降级
   132      // opCode 2为升级
   133      // opCode 1为移除
   134      //add node to blacklist application
   135      function makeProposeForRoleChange(string memory _nodeId, string memory _opCode,string memory _voterNodeId) checkInitStatus() public payable {
   136          require(_isAdminRole(_voterNodeId,msg.sender), "the role is not admin!");
   137          if (_strEqual(_opCode,opExit) || _strEqual(_opCode,opCommon)) {//如果操作类型是剔除网络或者降级
   138              bytes32  nodeHash = hash256(bytes(_nodeId));
   139              Node memory nt = nodeMap[nodeHash];
   140              require(!nt.isOriginator, "主节点不允许退出");
   141          }
   142          require(_validatePropose(_nodeId, _opCode), "申请失败");
   143          bytes32 statKey = _buildStatMapKey(_nodeId,_opCode);
   144          Statistics memory statistics = Statistics(true,_nodeId, 0,0, _voterNodeId, _opCode,uint(0));
   145          statisticsMap[statKey]=statistics;
   146          //清空投票信息
   147          delete voterMap[statKey];
   148  
   149          emit ApplyByAdminNotify(_nodeId);
   150      }
   151      //不允许剔除已被剔除的节点,不允许升级已升级的节点,不允许降级已降级的节点
   152      function _validatePropose(string memory _nodeId, string memory _opCode) internal view returns(bool) {
   153          if (_strEqual(_opCode, opJoin)) {
   154              return false;
   155          }
   156          bytes32 nodeHash = hash256(bytes(_nodeId));
   157          if (bytes(nodeMap[nodeHash].nodeId).length != 0) {
   158              if (nodeMap[nodeHash].role == isolated) {
   159                  return false;
   160              }
   161              if (_strEqual(_opCode, opAdmin) && nodeMap[nodeHash].role == admin) {
   162                  return false;
   163              }
   164              if (_strEqual(_opCode, opCommon) && nodeMap[nodeHash].role == common) {
   165                  return false;
   166              }
   167          }
   168          return true;
   169      }
   170      //投赞成票
   171      function voteForRoleChange(string memory _nodeId, string memory _voterNodeId,string memory _opCode) checkInitStatus() public payable {
   172          if (!_isAdminRole(_voterNodeId,msg.sender)){
   173              emit isAdminRoleEvent(_voterNodeId,msg.sender);
   174          }
   175          require(_isAdminRole(_voterNodeId,msg.sender), "the role is must be admin!");//the verify node must be admin role.
   176          if (_isVoted(_nodeId, _opCode,_voterNodeId)){
   177              emit isVotedEvent(_nodeId, _opCode,_voterNodeId);
   178          }
   179          require(!_isVoted(_nodeId, _opCode,_voterNodeId),"已经投过票");
   180          if(_strEqual(_opCode,opAdmin)){
   181              //common=>admin
   182              //必须是普通节点才可以升级到管理节点
   183              require(_isCommonRole(_nodeId), "the node must be normal role");//if node is not normal role, it cann't upgrade.
   184              //更新票数
   185              Statistics memory statistics = _updateStatistic(_nodeId, _opCode,_voterNodeId,msg.sender);
   186              //获取赞成票数
   187              uint count = uint(statistics.agree);
   188              //保存投票者信息
   189              _insertVoter(_nodeId,_opCode, _voterNodeId);
   190              //当满足半数以上规则且投票未结束才可更新节点角色
   191              if (count > adminCount / 2 && statistics.status == 0) {
   192                  //更新投票状态,投票完成
   193                  bytes32 statKeyHash = hash256(bytes(_strConcat(_nodeId,_opCode)));
   194                  _finishStatStatus(statKeyHash);
   195                  delete voterMap[statKeyHash];
   196                  //更新角色(common=>admin)
   197                  bytes32 nodeHash = hash256(bytes(_nodeId));
   198                  nodeMap[nodeHash].role = admin;
   199                  adminCount++;
   200                  emit VerifyNotify(_nodeId,admin,nodeMap[nodeHash].ip,nodeMap[nodeHash].port);
   201              }
   202          }else if(_strEqual(_opCode,opCommon)){
   203              bytes32 keyHash=hash256(bytes(_nodeId));
   204              //admin=>common
   205              require(isAdmin(keyHash), "the node must be admin!");//the apply node must be admin role.
   206              //更新票数
   207              Statistics memory statistics = _updateStatistic(_nodeId, _opCode,_voterNodeId,msg.sender);
   208              //获取赞成票数
   209              uint count = uint(statistics.agree);
   210              //保存投票者信息
   211              _insertVoter(_nodeId,_opCode, _voterNodeId);
   212              if (count > adminCount / 2 && statistics.status == 0) {//当满足半数以上规则且投票未结束才可更新节点角色
   213                  //更新投票状态,投票完成
   214                  bytes32 statKeyHash = hash256(bytes(_strConcat(_nodeId,_opCode)));
   215                  _finishStatStatus(statKeyHash);
   216                  delete voterMap[statKeyHash]; //删除投票过程
   217                  //更新角色(admin=>common)
   218                  bytes32 nodeHash = hash256(bytes(_nodeId));
   219                  nodeMap[nodeHash].role = common;
   220                  adminCount--;
   221                  emit VerifyNotify(_nodeId,common,nodeMap[nodeHash].ip,nodeMap[nodeHash].port);
   222              }
   223  
   224          }else if(_strEqual(_opCode,opExit)){
   225  
   226              //更新票数
   227              Statistics memory statistics = _updateStatistic(_nodeId, _opCode,_voterNodeId,msg.sender);
   228              //获取赞成票数
   229              uint count = uint(statistics.agree);
   230              //保存投票者信息
   231              _insertVoter(_nodeId,_opCode, _voterNodeId);
   232              //当满足半数以上规则且投票未结束才可更新节点角色
   233              if (count > adminCount / 2 && statistics.status == 0) {
   234                  //更新投票状态
   235                  bytes32 statKeyHash = hash256(bytes(_strConcat(_nodeId,_opCode)));
   236                  _finishStatStatus(statKeyHash);
   237                  delete voterMap[statKeyHash]; //删除投票过程
   238                  bytes32 nodeHash = hash256(bytes(_nodeId));
   239                  if (nodeMap[nodeHash].role == admin) {
   240                      adminCount--;
   241                  }
   242                  //更新角色(admin,common=>isolated)
   243                  nodeMap[nodeHash].role = isolated;
   244                  nodeMap[nodeHash].exist=false;
   245                  emit VerifyNotify(_nodeId,isolated,nodeMap[nodeHash].ip,nodeMap[nodeHash].port);
   246              }
   247          }
   248      }
   249  
   250  
   251  
   252      //获取管理员个数
   253      function getAdminCount() public view returns (uint) {
   254          return adminCount;
   255      }
   256      //tools function
   257      function hash256(bytes memory _hashStr) internal pure returns (bytes32) {
   258          return keccak256(_hashStr);
   259      }
   260  
   261      function isAdmin(bytes32 _nodeHash) public view returns (bool) {
   262          if(nodeMap[_nodeHash].exist){
   263              return nodeMap[_nodeHash].role == admin;
   264          }
   265          return false;
   266      }
   267      function _strConcat(string memory _a, string memory _b) internal pure returns (string memory){
   268          bytes memory _ba = bytes(_a);
   269          bytes memory _bb = bytes(_b);
   270          string memory ret = new string(_ba.length + _bb.length);
   271          bytes memory bret = bytes(ret);
   272          uint k = 0;
   273          for (uint i = 0; i < _ba.length; i++)bret[k++] = _ba[i];
   274          for (uint i = 0; i < _bb.length; i++) bret[k++] = _bb[i];
   275          return string(ret);
   276      }
   277  
   278      //设置联盟创始节点
   279      function setAdminNode(string memory _nodeId, string memory _ip, string memory _port, string memory _nodeName, address _nodeAddress) public
   280      checkNetworkStatus() {
   281          bytes32 key = hash256(bytes(_nodeId));
   282          require(!isAdmin(key),"节点已经是联盟创始节点");
   283          nodeMap[key].nodeId = _nodeId;
   284          nodeMap[key].ip = _ip;
   285          nodeMap[key].port = _port;
   286          nodeMap[key].nodeName = _nodeName;
   287          nodeMap[key].role = admin;
   288          nodeMap[key].nodeAddress = _nodeAddress;
   289          nodeMap[key].isOriginator = true;//联盟创始节点
   290          nodeMap[key].createdAt=block.timestamp;
   291          nodeMap[key].exist=true;
   292          nodeIds.push(bytes(_nodeId));
   293          existNodeIds[key]=true;
   294          adminCount++;
   295          originators.push(_nodeAddress);
   296          emit VerifyNotify(_nodeId, admin,nodeMap[key].ip,nodeMap[key].port);
   297      }
   298      //执行完这个方法以后,就不能再添加联盟创世节点
   299      //After this method is executed, it is not allowed to modify the administrator
   300      function initFinish() public checkNetworkStatus() {
   301          if(adminCount>0){
   302              networkStatus = true;
   303              emit networkInitComplete(block.number,block.timestamp);
   304          }
   305      }
   306      function _strEqual(string memory s1, string memory s2) internal pure returns (bool) {
   307          return keccak256(abi.encode(s1))== keccak256(abi.encode(s2));
   308      }
   309      //check pass
   310      //query method
   311      //返回同一个类型的节点的nodeId的数组
   312      function getNodeByRole(uint _role) public view returns (string memory) {
   313          string memory ret = "";
   314          //只有 0 1 2 三个可能值
   315          if (_role>2){
   316              return ret;
   317          }
   318          for (uint i = 0; i < nodeIds.length; i++) {
   319              bytes32 key = hash256(nodeIds[i]);
   320              string memory nodeId = nodeMap[key].nodeId;
   321              uint role = nodeMap[key].role;
   322              if (role == _role) {
   323                  ret = _strConcat(_strConcat(nodeId, ","), ret);
   324              }
   325          }
   326          return ret;
   327      }
   328  
   329      //check pass
   330      //根据节点nodeId返回节点详细信息
   331      function getNodeMap(string memory _nodeId) public view returns (string memory,string memory,string memory,string memory,address, uint,bool,uint) {
   332          bytes32 key = hash256(bytes(_nodeId));
   333          Node memory info = nodeMap[key];
   334          return (info.nodeId,info.ip,info.port,info.nodeName,info.nodeAddress,info.role,info.isOriginator,info.createdAt);
   335  
   336      }
   337      //check pass
   338      //根据节点名称返回节点详细信息
   339      function getInfoByName(string memory _nodeName) public view returns (string memory,string memory,string memory,string memory,address, uint,bool,uint) {
   340          for (uint i = 0; i < nodeIds.length; i++) {
   341              bytes32 key = hash256(nodeIds[i]);
   342              if (_strEqual(_nodeName, nodeMap[key].nodeName)) {
   343                  Node memory info = nodeMap[key];
   344                  return (info.nodeId,info.ip,info.port,info.nodeName,info.nodeAddress,info.role,info.isOriginator,info.createdAt);
   345              }
   346          }
   347          return ("","","","",address(0),0,false,0);
   348      }
   349      //check pass
   350      //初始的管理员是否已经完成
   351      function isInitFinished() public view returns (bool) {
   352          return networkStatus;
   353      }
   354      //add new node application
   355      //申请添加新节点
   356      function makeProposeForAddNewNode(string memory _nodeId, string memory _ip, string memory _port, string memory nodeName, address _nodeAddress, string memory _proposeNodeId) checkInitStatus() public payable {
   357  
   358          bytes32 statKey = _buildStatMapKey(_nodeId, opJoin);
   359  
   360          bytes32 nodeHash = hash256(bytes(_nodeId));
   361  
   362          require(!(nodeMap[nodeHash].exist),"节点已经存在");
   363  
   364          Statistics memory statistics = Statistics(true,_nodeId, 0,0, _proposeNodeId, opJoin,uint(0));
   365  
   366          statisticsMap[statKey]=statistics;
   367  
   368          //将节点作为游离节点加入到nodeMap中,isolated表示游离节点
   369          _insertNodeMap(_nodeId, _ip, _port, nodeName, _nodeAddress, isolated, nodeHash);
   370          //提交事件
   371          emit AddNewNodeNotify(_nodeId, _ip, _port);
   372      }
   373      //给申请的节点投票
   374      function voteForNewNodeApply(string memory _nodeId, string memory _voterNodeId)checkInitStatus() public payable {
   375          if (!_isAdminRole(_voterNodeId,msg.sender)){
   376              emit isAdminRoleEvent(_voterNodeId,msg.sender);
   377          }
   378          require(_isAdminRole(_voterNodeId,msg.sender), "the role is not admin!");
   379  
   380          if (_isVoted(_nodeId, opJoin,_voterNodeId)){
   381              emit isVotedEvent(_nodeId, opJoin,_voterNodeId);
   382          }
   383          require(!_isVoted(_nodeId, opJoin,_voterNodeId),"已经投过票");
   384  
   385          Statistics memory statistics = _updateStatistic(_nodeId,opJoin,_voterNodeId,msg.sender);
   386  
   387          _insertVoter(_nodeId, opJoin, _voterNodeId);//保存投票者信息
   388  
   389          uint count = uint(statistics.agree);
   390          if (count > adminCount / 2 && statistics.status == 0) {//当满足半数以上规则且投票未结束才可更新节点角色
   391              bytes32 statKeyHash = _buildStatMapKey(_nodeId,opJoin);
   392              bytes32 nodeHash = hash256(bytes(_nodeId));
   393              _finishStatStatus(statKeyHash);//更新投票状态
   394              delete voterMap[statKeyHash]; //删除投票过程
   395              //更新节点角色(role)
   396              nodeMap[nodeHash].role = common;
   397              emit VerifyNotify(_nodeId, common,nodeMap[nodeHash].ip,nodeMap[nodeHash].port);
   398          }
   399      }
   400      //插入nodeMap中
   401      function _insertNodeMap(string memory _nodeId, string memory _ip, string memory _port, string memory _nodeName, address _nodeAddress, uint _role, bytes32 _nodeHash) internal {
   402          nodeMap[_nodeHash].ip = _ip;
   403          nodeMap[_nodeHash].port = _port;
   404          nodeMap[_nodeHash].nodeId = _nodeId;
   405          nodeMap[_nodeHash].nodeAddress = _nodeAddress;
   406          nodeMap[_nodeHash].nodeName = _nodeName;
   407          nodeMap[_nodeHash].role = _role;
   408          nodeMap[_nodeHash].isOriginator=false;
   409          nodeMap[_nodeHash].createdAt=block.timestamp;
   410          nodeMap[_nodeHash].exist=true;
   411          //保持唯一性
   412          if (!existNodeIds[_nodeHash]){
   413              nodeIds.push(bytes(_nodeId));
   414              existNodeIds[_nodeHash]=true;
   415          }
   416      }
   417  
   418      //检查是否管理角色
   419      function _isAdminRole(string memory _nodeId,address _sender) internal view returns (bool) {
   420          bytes32 keyHash = hash256(bytes(_nodeId));
   421          if (!isAdmin(keyHash))
   422          {
   423              return false;
   424          }
   425          return nodeMap[keyHash].nodeAddress == _sender;
   426      }
   427      //检查给定节点是游离节点
   428      function _isIsolatedRole(string memory _nodeId) internal view returns (bool) {
   429          bytes32 key = hash256(bytes(_nodeId));
   430          bool f1 = existNodeIds[key];
   431          bool f2 = nodeMap[key].role == isolated;
   432          return (f1&&f2)||!f1;
   433      }
   434  
   435      //检查给定节点是普通节点
   436      function _isCommonRole(string memory _nodeId) internal  view returns (bool) {
   437          bytes32 key = hash256(bytes(_nodeId));
   438          bool f1 = existNodeIds[key];
   439          bool f2 = nodeMap[key].role == common;
   440          return (f1&&f2);
   441      }
   442  
   443      function _updateStatistic(string memory _nodeId,string memory _opCode, string memory _voterNodeId, address _voterAddress) internal returns (Statistics memory) {
   444          bytes32 statKeyHash = _buildStatMapKey(_nodeId, _opCode);
   445          VoteRecord memory record=VoteRecord(_nodeId, _voterNodeId, _voterAddress,_opCode,true);
   446          voteRecords.push(record);
   447          Statistics memory statistics = statisticsMap[statKeyHash];
   448          statistics.agree += 1;
   449          statisticsMap[statKeyHash] = statistics;
   450          return statistics;
   451      }
   452      function _buildStatMapKey(string memory _eNodeStr, string memory opCode) internal pure returns (bytes32) {
   453          string memory statKey = _strConcat(_eNodeStr, opCode);
   454          return hash256(bytes(statKey));
   455      }
   456      function _finishStatStatus(bytes32 statKeyHash) internal {
   457          Statistics memory statistics = statisticsMap[statKeyHash];
   458          statistics.status = 1;
   459          statisticsMap[statKeyHash] = statistics;
   460      }
   461      function _insertVoter(string memory _nodeId,string memory _opCode, string memory _voterNodeId) internal {
   462          bytes32 key = hash256(bytes(_strConcat(_nodeId,_opCode)));
   463          voterMap[key].push(_voterNodeId);
   464      }
   465      //根据state key 获取投票统计信息
   466      function getLastStatistics(string memory _nodeId, string memory _opCode) public view returns (uint, uint,string memory, string memory, uint) {
   467          string memory key = _strConcat(_nodeId, _opCode);
   468          bytes32 nodeHash= hash256(bytes(key));
   469          Statistics memory statistics = statisticsMap[nodeHash];
   470          return (statistics.agree,statistics.disagree,statistics.proposeNodeId,statistics.opCode,statistics.status);
   471      }
   472      //查询所有投票未完成的记录,返回字符串(enodeId+opType),以逗号分割
   473      function getAllStatingRecord() public view  returns (string memory) {
   474          string memory result = "";
   475          for (uint i=0;i<nodeIds.length;i++) {
   476              bytes32 nodeHash = hash256(bytes(nodeIds[i]));
   477              string memory record = _getStatingRecord(nodeHash);
   478              if (!_strEqual(record, "")) {
   479                  result = _strConcat(result, _strConcat(",", record));
   480              }
   481          }
   482          return result;
   483      }
   484      function _getStatingRecord(bytes32 _nodeHash) internal view returns (string memory) {
   485          string memory result = "";
   486          string memory nodeId = nodeMap[_nodeHash].nodeId;
   487          string memory tmp = _findStatingStatus(nodeId, opJoin);
   488          if (!_strEqual(tmp, "")) {
   489              result = tmp;
   490          }
   491          tmp = _findStatingStatus(nodeId, opExit);
   492          if (!_strEqual(tmp, "")) {
   493              result = _strConcat(result, _strConcat(",", tmp));
   494          }
   495          tmp = _findStatingStatus(nodeId, opAdmin);
   496          if (!_strEqual(tmp, "")) {
   497              result = _strConcat(result, _strConcat(",", tmp));
   498          }
   499          tmp = _findStatingStatus(nodeId, opCommon);
   500          if (!_strEqual(tmp, "")) {
   501              result = _strConcat(result, _strConcat(",", tmp));
   502          }
   503          return result;
   504      }
   505      function _findStatingStatus(string memory _nodeId, string memory _opCode) internal view returns (string memory) {
   506          bytes32 key = _buildStatMapKey(_nodeId, _opCode);
   507          if (!statisticsMap[key].exist) {
   508              return "";
   509          }
   510          Statistics memory statistics = statisticsMap[key];
   511          //投票还在进行中,未完成
   512          if (statistics.status == 0) {
   513              return _strConcat(_nodeId, _opCode);
   514          }
   515          return "";
   516      }
   517      //投反对票
   518      //包括加入,升级,降级,退出
   519      function disagree(string memory _nodeId, string memory _voterNodeId,string memory _opCode) checkInitStatus() public payable {
   520          require(_isAdminRole(_voterNodeId,msg.sender), "the role must be admin!");
   521          bytes32 statKeyHash = _buildStatMapKey(_nodeId, _opCode);
   522          Statistics memory statistics = statisticsMap[statKeyHash];
   523          // 新增投票记录
   524          _addDisagreeVote(_nodeId, _voterNodeId,msg.sender,_opCode);
   525  
   526          //增加反对票的数量
   527          statistics.disagree += 1;
   528          if (uint(statistics.disagree) > adminCount / 2 && statistics.status == 0) {
   529              statistics.status = 1;
   530              if(_strEqual(_opCode,opJoin)){
   531                  nodeMap[hash256(bytes(_nodeId))].exist=false;
   532              }
   533              delete voterMap[statKeyHash]; //删除投票过程
   534          }
   535          statisticsMap[statKeyHash] = statistics;
   536      }
   537      function _addDisagreeVote(string memory _nodeId,string memory _voterNodeId,address _voterNodeAddress,string memory _opCode) internal {
   538          VoteRecord memory record;
   539          record.nodeId = _nodeId;
   540          record.voterNodeId = _voterNodeId;
   541          record.voterAddress = _voterNodeAddress;
   542          record.opCode=_opCode;
   543          record.auth = false;
   544          voteRecords.push(record);
   545          _insertVoter(_nodeId,_opCode, _voterNodeId);
   546      }
   547      //更新节点ip和端口信息
   548      function updateNodeInfo(string memory _nodeId,string memory _ip,string memory _port) public {
   549          bytes32 nodeHash = hash256(bytes(_nodeId));
   550          Node memory node = nodeMap[nodeHash];
   551          require((node.nodeAddress == msg.sender), "账号不匹配");
   552          node.ip = _ip;
   553          node.port = _port;
   554          nodeMap[nodeHash] = node;
   555      }
   556      //更新节点的名称
   557      function updateNodeName(string memory _nodeId,string memory _nodeName) public {
   558          bytes32 nodeHash = hash256(bytes(_nodeId));
   559          Node memory node = nodeMap[nodeHash];
   560          require((node.nodeAddress == msg.sender), "账号不匹配");
   561          node.nodeName = _nodeName;
   562          nodeMap[nodeHash] = node;
   563      }
   564      //退出网络,需要触发断开网络连接的事件,但主节点不允许退出
   565      function exit(string memory _nodeId) checkInitStatus() public {
   566          bytes32 key = hash256(bytes(_nodeId));
   567          if(nodeMap[key].exist==false){
   568              return ;
   569          }
   570          //校验是否已经退出网路
   571          Node memory nodeTable = nodeMap[key];
   572          require(!nodeTable.isOriginator, "主节点不允许退出");
   573          nodeMap[key].exist=false;
   574          emit VerifyNotify(_nodeId,  isolated,nodeMap[key].ip,nodeMap[key].port);
   575      }
   576      //查找该节点是否为本次申请投过票
   577      function _isVoted(string memory _nodeId,string memory _opCode, string memory _voterNodeId) internal view returns(bool){
   578          bytes32 key = hash256(bytes(_strConcat(_nodeId,_opCode)));
   579          string[] memory ids=voterMap[key];
   580          for(uint i=0;i<ids.length;i++){
   581              if(_strEqual(ids[i],_voterNodeId)){
   582                  return true;
   583              }
   584          }
   585          return false;
   586      }
   587      function getOriginators() public view returns(address[] memory){
   588          return originators;
   589      }
   590      function nodeExists(string memory _nodeId) public view returns (bool) {
   591          bytes32 key = hash256(bytes(_nodeId));
   592          Node memory node = nodeMap[key];
   593          return node.exist;
   594      }
   595  }