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