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 }