github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/contracts/chief/src/chief_0.0.5.sol (about)

     1  // Copyright 2018 The Smartmesh Chain Authors
     2  // This file is part of the Spectrum library.
     3  pragma solidity ^0.4.19;
     4  
     5  /*
     6  vsn 0.0.3 改进如下 :
     7      每个 epoch 增加了一个 黑名单,用来保存被淘汰的 signers ,以保证其不会重复被选拔;
     8      在每个 epoch 中按打包交易数量来清除 1/3 非 genesisSigners 的节点 ;
     9  
    10  vsn 0.0.4 修改 0.0.3 中的 bug
    11  vsn 0.0.5 修正bug , 调整修改 singerLimit 和 volunteerLimit 的逻辑
    12  */
    13  contract TribeChief_0_0_5 {
    14  
    15      string vsn = "0.0.5";
    16  
    17      //config >>>>
    18      uint init_epoch = 5760;
    19      uint init_singerLimit = 17;
    20      uint init_volunteerLimit = 70;
    21  
    22      uint epoch = init_epoch; // 5760 = 24H ; 11520 = 48H
    23      mapping(address => bool) genesisSigner; // genesis signer address
    24      uint singerLimit = init_singerLimit;
    25      uint volunteerLimit = init_volunteerLimit;
    26      //config <<<<
    27  
    28      uint blockNumber;
    29  
    30      //signer info
    31      struct SignerInfo {
    32          uint score;
    33          uint number;
    34      }
    35  
    36      address _owner;
    37  
    38      address[] _signerList;
    39      address[] _volunteerList;
    40      address[] _blackList;
    41  
    42      // the mapping of the signer score and the block number
    43      mapping(address => SignerInfo) signersMap;
    44      // the mapping of the volunteer and block number
    45      mapping(address => uint) volunteersMap;
    46      // the mapping of the blacklist and block number
    47      mapping(address => uint) blMap;
    48  
    49      function TribeChief_0_0_5(address[] genesisSigners) public {
    50          _owner = msg.sender;
    51          uint len = genesisSigners.length;
    52          if (len > 0) {
    53              for (uint i = 0; i < len; i++) {
    54                  address g = genesisSigners[i];
    55                  genesisSigner[g] = true;
    56                  pushSigner(g, 3);
    57              }
    58          } else {
    59              // normal default for testing
    60              address g1 = 0x4110bd1ff0b73fa12c259acf39c950277f266787;
    61              // nerver delete genesis signer
    62              genesisSigner[g1] = true;
    63              pushSigner(g1, 3);
    64          }
    65      }
    66  
    67      // delete a blacklist by index
    68      function deleteBlackList(uint index) private {
    69  
    70          uint blen = _blackList.length;
    71          if (index < blen) {
    72              delete blMap[_blackList[index]];
    73              for (uint i = index; i < blen - 1; i++) {
    74                  _blackList[i] = _blackList[i + 1];
    75              }
    76              _blackList.length -= 1;
    77          }
    78      }
    79  
    80      // delete a volunteer by index
    81      function deleteVolunteer(uint index) private {
    82  
    83          uint vlen = _volunteerList.length;
    84          // _signerList >>>>
    85          if (index < vlen) {
    86              delete volunteersMap[_volunteerList[index]];
    87              for (uint i = index; i < vlen - 1; i++) {
    88                  _volunteerList[i] = _volunteerList[i + 1];
    89              }
    90              _volunteerList.length -= 1;
    91          }
    92      }
    93  
    94      // delete a signer by index
    95      function deleteSigner(uint index) private {
    96          uint slen = _signerList.length;
    97          if (index < slen) {
    98              delete signersMap[_signerList[index]];
    99              for (uint i = index; i < slen - 1; i++) {
   100                  _signerList[i] = _signerList[i + 1];
   101              }
   102              _signerList.length -= 1;
   103          }
   104      }
   105  
   106      // append a sinner to blacklist
   107      function pushBlackList(address sinner) private {
   108  
   109          if (blMap[sinner] == 0) {
   110              _blackList.push(sinner);
   111              blMap[sinner] = block.number;
   112          }
   113      }
   114  
   115      // append a volunteer
   116      function pushVolunteer(address volunteer) private {
   117          //满员或者已经存在于签名人or候选人则不添加
   118          //vsn-0.0.3 : blMap is blacklist map , the new volunteer can not in blacklist
   119          if (_volunteerList.length < volunteerLimit && volunteersMap[volunteer] == 0 && blMap[volunteer] == 0 && signersMap[volunteer].number == 0) {
   120              _volunteerList.push(volunteer);
   121              volunteersMap[volunteer] = block.number;
   122          }
   123      }
   124  
   125      // generate a random index for remove signers every epoch
   126      function getRandomIdx(address addr, uint max) private view returns (uint256) {
   127          if (max <= 0) {
   128              return 0;
   129          }
   130          uint256 random = uint256(keccak256(addr, block.difficulty, now));
   131          return (random % max);
   132      }
   133  
   134      // append a signer
   135      function pushSigner(address signer, uint score) private {
   136  
   137          if (_signerList.length < singerLimit) {
   138              _signerList.push(signer);
   139              signersMap[signer].score = score;
   140              signersMap[signer].number = block.number;
   141          }
   142      }
   143  
   144      modifier apply(address _addr) {
   145          require(signersMap[_addr].number > 0);
   146          _;
   147      }
   148      modifier owner(address _addr) {
   149          require(_addr == _owner);
   150          _;
   151      }
   152  
   153      // v0.0.5 >>>>
   154      // before "apply" ,after "owner"
   155      function setVolunteerLimit(uint n) public owner(msg.sender) {
   156  
   157          require (n >= init_volunteerLimit);
   158  
   159          uint vlen = _volunteerList.length;
   160  
   161          if (n < vlen){
   162              for (uint i = n; i < vlen; i ++){
   163                  delete volunteersMap[_volunteerList[i]];
   164              }
   165              //删除尾部多余
   166              _volunteerList.length -= (vlen - n);
   167          }
   168  
   169          volunteerLimit = n;
   170      }
   171  
   172      function setSingerLimit(uint n) public owner(msg.sender) {
   173  
   174          require (n >= init_singerLimit);
   175  
   176          uint slen = _signerList.length;
   177  
   178          if (n < slen){
   179              for(uint i = n; i < slen; i ++){
   180                  delete signersMap[_signerList[i]];
   181              }
   182              _signerList.length -= (slen - n);
   183          }
   184  
   185          singerLimit = n;
   186      }
   187  
   188      function setEpoch(uint n) public owner(msg.sender) {
   189  
   190          require (n >= init_epoch);
   191  
   192          epoch = n;
   193      }
   194      // v0.0.5 <<<<
   195  
   196      function repeatTi(uint[] tiList, uint ti) private pure returns (bool) {
   197          if (tiList.length > 0) {
   198              for (uint i = 0; i < tiList.length; i++) {
   199                  if (tiList[i] == ti) {
   200                      return true;
   201                  }
   202              }
   203          }
   204          return false;
   205      }
   206  
   207      // v0.0.2
   208      function _cleanVolunteerList() private {
   209          uint vlen = _volunteerList.length;
   210          for (uint i1 = 0; i1 < vlen; i1++) {
   211              delete volunteersMap[_volunteerList[i1]];
   212          }
   213          delete _volunteerList;
   214      }
   215      // v0.0.4
   216      function _cleanBlacklist() private {
   217          // 1 : clean blacklist
   218          uint blen = _blackList.length;
   219          for (uint i2 = 0; i2 < blen; i2++) {
   220              delete blMap[_blackList[i2]];
   221          }
   222          delete _blackList;
   223      }
   224      // v0.0.4
   225      function _moveSignersToBlacklist() private {
   226          uint counter = 0;
   227          uint[] memory tiList = new uint[](slen);
   228          uint slen = _signerList.length;
   229          // target signer idx
   230          for (uint i3 = 0 ; i3 < slen ; i3++) {
   231              address _addr = _signerList[i3];
   232              uint ti = getRandomIdx(_addr, (slen - uint(1)));
   233              //skip out of range
   234              if (ti >= slen) {
   235                  continue;
   236              }
   237              address _signer = _signerList[ti];
   238              //skip genesis signer
   239              if (genesisSigner[_signer])
   240                  continue;
   241              //skip repeat
   242              if (repeatTi(tiList, ti))
   243                  continue;
   244              tiList[counter] = ti;
   245              if (counter >= (slen / uint(3)))
   246                  break;
   247              counter += uint(1);
   248          }
   249          if (counter > 0) {
   250              for (uint i4 = 0; i4 < slen; i4++) {
   251                  uint idx = tiList[i4];
   252                  // skip nil , 0 == nil
   253                  if (idx != 0) {
   254                      pushBlackList(_signerList[tiList[i4]]);
   255                      deleteSigner(tiList[i4]);
   256                  }
   257              }
   258          }
   259      }
   260  
   261      function update(address volunteer) public apply(msg.sender) {
   262  
   263          blockNumber = block.number;
   264  
   265          // vsn-0.0.2 : every epoch be clean volunteers
   266          // vsn-0.0.3 : clean blacklist and move 1/3 signers to blacklist excelude genesisSigners
   267          if (block.number > epoch && block.number % epoch == 0) {
   268              // ==== vsn-0.0.2 ====
   269              _cleanVolunteerList();
   270              // ==== vsn-0.0.3 ====
   271              // ==== vsn-0.0.4 ====
   272              // 1 : clean blacklist
   273              _cleanBlacklist();
   274              // 2 : move 1/3 signers to blacklist
   275              _moveSignersToBlacklist();
   276          }
   277  
   278          // mine
   279          // 如果当前块 不是 signers[ blockNumber % signers.length ] 出的,就给这个 signer 减分
   280          // 否则恢复成 3 分
   281          uint signerIdx = blockNumber % _signerList.length;
   282          //初始签名人不做处理
   283          if (!genesisSigner[_signerList[signerIdx]]) {
   284  
   285              SignerInfo storage signer = signersMap[_signerList[signerIdx]];
   286  
   287              // 序号对应的不是我,则扣它一分
   288              if (msg.sender != _signerList[signerIdx]) {
   289                  if (signer.score > 1) {
   290                      signer.score -= 1;
   291                      signer.number = blockNumber;
   292                  } else {
   293                      // move to blacklist and cannot be selected in this epoch
   294                      pushBlackList(_signerList[signerIdx]);
   295                      // vsn-0.0.3
   296                      // score == 0 , remove on signerList
   297                      deleteSigner(signerIdx);
   298                  }
   299              } else {
   300                  // 恢复分数
   301                  signer.score = 3;
   302              }
   303          }
   304  
   305          // tag
   306          if (volunteer != uint160(0)) {
   307              pushVolunteer(volunteer);
   308          }
   309  
   310          //是否提拔一个人到签名人
   311          if (_signerList.length < singerLimit && _volunteerList.length > 0) {
   312  
   313              //将候选人列表首个添加到签名人列表
   314              pushSigner(_volunteerList[0], 3);
   315  
   316              //删除该候补志愿者
   317              deleteVolunteer(0);
   318          }
   319      }
   320  
   321      function version() public constant returns (string) {
   322          return vsn;
   323      }
   324  
   325      function getSignerLimit() public constant returns (uint) {
   326          return singerLimit;
   327      }
   328  
   329      function getEpoch() public constant returns (uint) {
   330          return epoch;
   331      }
   332  
   333      function getVolunteerLimit() public constant returns (uint) {
   334          return volunteerLimit;
   335      }
   336  
   337      function getStatus() public constant returns (
   338          address[] volunteerList,
   339          address[] signerList,
   340          address[] blackList, // vsn 0.0.3
   341          uint[] memory scoreList,
   342          uint[] memory numberList,
   343          uint number
   344      ) {
   345          scoreList = new uint[](_signerList.length);
   346          numberList = new uint[](_signerList.length);
   347          for (uint i = 0; i < _signerList.length; i ++) {
   348              scoreList[i] = signersMap[_signerList[i]].score;
   349              numberList[i] = signersMap[_signerList[i]].number;
   350          }
   351          volunteerList = _volunteerList;
   352          signerList = _signerList;
   353          blackList = _blackList;
   354          // vsn 0.0.3
   355          number = blockNumber;
   356          return;
   357      }
   358  
   359  }