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 }