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