github.com/klaytn/klaytn@v1.12.1/contracts/reward/contract/AddressBook.sol (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 pragma solidity ^0.4.24; 18 import "./SafeMath.sol"; 19 20 /** 21 * @title AddressBook 22 */ 23 24 contract AddressBook { 25 using SafeMath for uint256; 26 /* 27 * Events 28 */ 29 event DeployContract(string contractType, address[] adminList, uint256 requirement); 30 event AddAdmin (address indexed admin); 31 event DeleteAdmin(address indexed admin); 32 event UpdateRequirement(uint256 requirement); 33 event ClearRequest(); 34 event SubmitRequest(bytes32 indexed id, address indexed from, Functions functionId, bytes32 firstArg, bytes32 secondArg, bytes32 thirdArg, address[] confirmers); 35 event ExpiredRequest(bytes32 indexed id, address indexed from, Functions functionId, bytes32 firstArg, bytes32 secondArg, bytes32 thirdArg, address[] confirmers); 36 event RevokeRequest(bytes32 indexed id, address indexed from, Functions functionId, bytes32 firstArg, bytes32 secondArg, bytes32 thirdArg, address[] confirmers); 37 event CancelRequest(bytes32 indexed id, address indexed from, Functions functionId, bytes32 firstArg, bytes32 secondArg, bytes32 thirdArg); 38 event ExecuteRequestSuccess(bytes32 indexed id, address indexed from, Functions functionId, bytes32 firstArg, bytes32 secondArg, bytes32 thirdArg); 39 event ExecuteRequestFailure(bytes32 indexed id, address indexed from, Functions functionId, bytes32 firstArg, bytes32 secondArg, bytes32 thirdArg); 40 41 event ActivateAddressBook(); 42 event UpdatePocContract(address prevPocContractAddress, uint256 prevVersion, address curPocContractAddress, uint256 curVersion); 43 event UpdateKirContract(address prevKirContractAddress, uint256 prevVersion, address curKirContractAddress, uint256 curVersion); 44 event UpdateSpareContract(address spareContractAddress); 45 event RegisterCnStakingContract(address cnNodeId, address cnStakingContractAddress, address cnRewardAddress); 46 event UnregisterCnStakingContract(address cnNodeId); 47 event ReviseRewardAddress(address cnNodeId, address prevRewardAddress, address curRewardAddress); 48 49 /* 50 * Constants 51 */ 52 uint256 constant public MAX_ADMIN = 50; 53 uint256 constant public MAX_PENDING_REQUEST = 100; 54 string constant public CONTRACT_TYPE = "AddressBook"; 55 uint8 constant public CN_NODE_ID_TYPE = 0; 56 uint8 constant public CN_STAKING_ADDRESS_TYPE = 1; 57 uint8 constant public CN_REWARD_ADDRESS_TYPE = 2; 58 uint8 constant public POC_CONTRACT_TYPE = 3; 59 uint8 constant public KIR_CONTRACT_TYPE = 4; 60 uint256 constant public ONE_WEEK = 1 weeks; 61 uint256 constant public TWO_WEEKS = 2 weeks; 62 uint256 constant public VERSION = 1; 63 64 enum RequestState {Unknown, NotConfirmed, Executed, ExecutionFailed, Expired} 65 enum Functions {Unknown, AddAdmin, DeleteAdmin, UpdateRequirement, ClearRequest, ActivateAddressBook, UpdatePocContract, UpdateKirContract, RegisterCnStakingContract, UnregisterCnStakingContract, UpdateSpareContract} 66 67 struct Request { 68 Functions functionId; 69 bytes32 firstArg; 70 bytes32 secondArg; 71 bytes32 thirdArg; 72 address[] confirmers; 73 uint256 initialProposedTime; 74 RequestState state; 75 } 76 77 /* 78 * Storage 79 */ 80 address[] private adminList; 81 uint256 public requirement; 82 mapping (address => bool) private isAdmin; 83 mapping(bytes32 => Request) private requestMap; 84 bytes32 [] private pendingRequestList; 85 86 address public pocContractAddress; 87 address public kirContractAddress; 88 address public spareContractAddress; 89 90 mapping(address => uint256) private cnIndexMap; 91 address[] private cnNodeIdList; 92 address[] private cnStakingContractList; 93 address[] private cnRewardAddressList; 94 95 bool public isActivated; 96 bool public isConstructed; 97 98 /* 99 * Modifiers 100 */ 101 modifier onlyMultisigTx() { 102 require(msg.sender == address(this), "Not a multisig-transaction."); 103 _; 104 } 105 106 modifier onlyAdmin(address _admin) { 107 require(isAdmin[_admin], "Address is not admin."); 108 _; 109 } 110 111 modifier adminDoesNotExist(address _admin) { 112 require(!isAdmin[_admin], "Admin already exits."); 113 _; 114 } 115 116 modifier notNull(address _address) { 117 require(_address != 0, "Address is null."); 118 _; 119 } 120 121 modifier validRequirement(uint256 _adminCount, uint256 _requirement) { 122 require(_adminCount <= MAX_ADMIN 123 && _requirement <= _adminCount 124 && _requirement != 0 125 && _adminCount != 0, "Invalid requirement."); 126 _; 127 } 128 129 130 /* 131 * Constructor 132 */ 133 function constructContract(address[] _adminList, uint256 _requirement) external 134 validRequirement(_adminList.length, _requirement) { 135 require(msg.sender == 0x88bb3838aa0a140aCb73EEb3d4B25a8D3aFD58D4, "Invalid sender."); 136 require(isConstructed == false, "Already constructed."); 137 uint256 adminListCnt = _adminList.length; 138 139 isActivated = false; 140 for (uint256 i = 0; i < adminListCnt; i++) { 141 require(!isAdmin[_adminList[i]] && _adminList[i] != 0, "Address is null or not unique."); 142 isAdmin[_adminList[i]] = true; 143 } 144 adminList = _adminList; 145 requirement = _requirement; 146 isConstructed = true; 147 emit DeployContract(CONTRACT_TYPE, adminList, requirement); 148 } 149 150 /* 151 * Private functions 152 */ 153 function deleteFromPendingRequestList(bytes32 id) private { 154 uint256 pendingRequestListCnt = pendingRequestList.length; 155 for(uint256 i = 0; i < pendingRequestListCnt; i++){ 156 if(id == pendingRequestList[i]){ 157 if(i != pendingRequestListCnt - 1) { 158 pendingRequestList[i] = pendingRequestList[pendingRequestListCnt - 1]; 159 } 160 delete pendingRequestList[pendingRequestListCnt - 1]; 161 pendingRequestList.length = pendingRequestList.length.sub(1); 162 break; 163 } 164 } 165 } 166 167 function getId(Functions _functionId, bytes32 _firstArg, bytes32 _secondArg, bytes32 _thirdArg) private pure returns(bytes32) { 168 return keccak256(abi.encodePacked(_functionId,_firstArg,_secondArg,_thirdArg)); 169 } 170 171 function submitRequest(Functions _functionId, bytes32 _firstArg, bytes32 _secondArg, bytes32 _thirdArg) private { 172 bytes32 id = getId(_functionId,_firstArg,_secondArg,_thirdArg); 173 174 if(requestMap[id].initialProposedTime != 0) { 175 if (requestMap[id].initialProposedTime + TWO_WEEKS < now) { 176 deleteFromPendingRequestList(id); 177 delete requestMap[id]; 178 } 179 else if (requestMap[id].initialProposedTime + ONE_WEEK < now) { 180 if (requestMap[id].state != RequestState.Expired) { 181 requestMap[id].state = RequestState.Expired; 182 } 183 emit ExpiredRequest(id, msg.sender, _functionId, _firstArg, _secondArg, _thirdArg, requestMap[id].confirmers); 184 } 185 // Confirm 186 else if (requestMap[id].initialProposedTime <= now){ 187 uint256 confirmersCnt = requestMap[id].confirmers.length; 188 for(uint256 i = 0; i < confirmersCnt; i++){ 189 require(msg.sender != requestMap[id].confirmers[i], "Msg.sender already requested."); 190 } 191 requestMap[id].confirmers.push(msg.sender); 192 emit SubmitRequest(id, msg.sender, _functionId, _firstArg, _secondArg, _thirdArg, requestMap[id].confirmers); 193 } 194 } 195 196 if (requestMap[id].initialProposedTime == 0) { 197 if (pendingRequestList.length >= MAX_PENDING_REQUEST) { 198 require(_functionId == Functions.ClearRequest, "Request list is full."); 199 } 200 requestMap[id] = Request({ 201 functionId : _functionId, 202 firstArg : _firstArg, 203 secondArg : _secondArg, 204 thirdArg : _thirdArg, 205 initialProposedTime : now, 206 confirmers : new address[](0), 207 state : RequestState.NotConfirmed 208 }); 209 requestMap[id].confirmers.push(msg.sender); 210 pendingRequestList.push(id); 211 emit SubmitRequest(id, msg.sender, _functionId, _firstArg, _secondArg, _thirdArg, requestMap[id].confirmers); 212 } 213 } 214 215 function executeRequest(bytes32 _id) private { 216 bool executed = false; 217 Request memory _executeRequest = requestMap[_id]; 218 219 if (_executeRequest.functionId == Functions.AddAdmin) { 220 //bytes4(keccak256("addAdmin(address)")) => 0x70480275 221 executed = address(this).call(0x70480275, address(_executeRequest.firstArg)); 222 } 223 else if (_executeRequest.functionId == Functions.DeleteAdmin) { 224 //bytes4(keccak256("deleteAdmin(address)")) => 0x27e1f7df 225 executed = address(this).call(0x27e1f7df, address(_executeRequest.firstArg)); 226 } 227 else if (_executeRequest.functionId == Functions.UpdateRequirement) { 228 //bytes4(keccak256("updateRequirement(uint256)")) => 0xc47afb3a 229 executed = address(this).call(0xc47afb3a, uint256(_executeRequest.firstArg)); 230 } 231 else if (_executeRequest.functionId == Functions.ClearRequest) { 232 //bytes4(keccak256("clearRequest()")) => 0x4f97638f 233 executed = address(this).call(0x4f97638f); 234 } 235 else if (_executeRequest.functionId == Functions.ActivateAddressBook) { 236 //bytes4(keccak256("activateAddressBook()")) => 0xcec92466 237 executed = address(this).call(0xcec92466); 238 } 239 else if (_executeRequest.functionId == Functions.UpdatePocContract) { 240 //bytes4(keccak256("updatePocContract(address,uint256)")) => 0xc7e9de75 241 executed = address(this).call(0xc7e9de75, address(_executeRequest.firstArg), uint256(_executeRequest.secondArg)); 242 } 243 else if (_executeRequest.functionId == Functions.UpdateKirContract) { 244 //bytes4(keccak256("updateKirContract(address,uint256)")) => 0x4c5d435c 245 executed = address(this).call(0x4c5d435c, address(_executeRequest.firstArg), uint256(_executeRequest.secondArg)); 246 } 247 else if (_executeRequest.functionId == Functions.RegisterCnStakingContract) { 248 //bytes4(keccak256("registerCnStakingContract(address,address,address)")) => 0x298b3c61 249 executed = address(this).call(0x298b3c61, address(_executeRequest.firstArg), address(_executeRequest.secondArg), address(_executeRequest.thirdArg)); 250 } 251 else if (_executeRequest.functionId == Functions.UnregisterCnStakingContract) { 252 //bytes4(keccak256("unregisterCnStakingContract(address)")) => 0x579740db 253 executed = address(this).call(0x579740db, address(_executeRequest.firstArg)); 254 } 255 else if (_executeRequest.functionId == Functions.UpdateSpareContract) { 256 //bytes4(keccak256("updateSpareContract(address)")) => 0xafaaf330 257 executed = address(this).call(0xafaaf330, address(_executeRequest.firstArg)); 258 } 259 260 deleteFromPendingRequestList(_id); 261 if(executed) { 262 if(requestMap[_id].initialProposedTime != 0) { 263 requestMap[_id].state = RequestState.Executed; 264 } 265 emit ExecuteRequestSuccess(_id, msg.sender, _executeRequest.functionId, _executeRequest.firstArg, _executeRequest.secondArg, _executeRequest.thirdArg); 266 } else { 267 if(requestMap[_id].initialProposedTime != 0) { 268 requestMap[_id].state = RequestState.ExecutionFailed; 269 } 270 emit ExecuteRequestFailure(_id, msg.sender, _executeRequest.functionId, _executeRequest.firstArg, _executeRequest.secondArg, _executeRequest.thirdArg); 271 } 272 } 273 274 function checkQuorum(bytes32 _id) private view returns(bool) { 275 return (requestMap[_id].confirmers.length >= requirement); 276 } 277 278 /* 279 * external functions 280 */ 281 function revokeRequest(Functions _functionId, bytes32 _firstArg, bytes32 _secondArg, bytes32 _thirdArg) external 282 onlyAdmin(msg.sender) { 283 bytes32 id = getId(_functionId,_firstArg,_secondArg,_thirdArg); 284 285 require(requestMap[id].initialProposedTime != 0, "Invalid request."); 286 require(requestMap[id].state == RequestState.NotConfirmed, "Must be at not-confirmed state."); 287 bool foundIt = false; 288 uint256 confirmerCnt = requestMap[id].confirmers.length; 289 290 for(uint256 i = 0; i < confirmerCnt; i++){ 291 if(msg.sender == requestMap[id].confirmers[i]){ 292 foundIt = true; 293 294 if (requestMap[id].initialProposedTime + ONE_WEEK < now) { 295 if (requestMap[id].initialProposedTime + TWO_WEEKS < now) { 296 deleteFromPendingRequestList(id); 297 delete requestMap[id]; 298 } 299 else { 300 requestMap[id].state = RequestState.Expired; 301 } 302 303 emit ExpiredRequest(id, msg.sender, _functionId, _firstArg, _secondArg, _thirdArg, requestMap[id].confirmers); 304 } 305 else { 306 if(i != confirmerCnt - 1) { 307 requestMap[id].confirmers[i] = requestMap[id].confirmers[confirmerCnt - 1]; 308 } 309 delete requestMap[id].confirmers[confirmerCnt - 1]; 310 requestMap[id].confirmers.length = requestMap[id].confirmers.length.sub(1); 311 312 emit RevokeRequest(id, msg.sender, requestMap[id].functionId, requestMap[id].firstArg, requestMap[id].secondArg, requestMap[id].thirdArg, requestMap[id].confirmers); 313 314 if(requestMap[id].confirmers.length == 0) { 315 deleteFromPendingRequestList(id); 316 delete requestMap[id]; 317 emit CancelRequest(id, msg.sender, requestMap[id].functionId, requestMap[id].firstArg, requestMap[id].secondArg, requestMap[id].thirdArg); 318 } 319 } 320 break; 321 } 322 } 323 require(foundIt, "Msg.sender has not requested."); 324 } 325 326 /* 327 * submit request functions 328 */ 329 function submitAddAdmin(address _admin) external 330 onlyAdmin(msg.sender) 331 adminDoesNotExist(_admin) 332 notNull(_admin) 333 validRequirement(adminList.length.add(1), requirement) { 334 bytes32 id = getId(Functions.AddAdmin,bytes32(_admin),0,0); 335 336 submitRequest(Functions.AddAdmin,bytes32(_admin),0,0); 337 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 338 executeRequest(id); 339 } 340 } 341 342 function submitDeleteAdmin(address _admin) external 343 onlyAdmin(_admin) 344 onlyAdmin(msg.sender) 345 notNull(_admin) 346 validRequirement(adminList.length.sub(1), requirement) { 347 bytes32 id = getId(Functions.DeleteAdmin,bytes32(_admin),0,0); 348 349 submitRequest(Functions.DeleteAdmin,bytes32(_admin),0,0); 350 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 351 executeRequest(id); 352 } 353 } 354 355 function submitUpdateRequirement(uint256 _requirement) external 356 onlyAdmin(msg.sender) 357 validRequirement(adminList.length, _requirement) { 358 require(requirement != _requirement, "Same requirement."); 359 bytes32 id = getId(Functions.UpdateRequirement,bytes32(_requirement),0,0); 360 361 submitRequest(Functions.UpdateRequirement,bytes32(_requirement),0,0); 362 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 363 executeRequest(id); 364 } 365 } 366 367 function submitClearRequest() external 368 onlyAdmin(msg.sender) { 369 bytes32 id = getId(Functions.ClearRequest,0,0,0); 370 371 submitRequest(Functions.ClearRequest,0,0,0); 372 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 373 executeRequest(id); 374 } 375 } 376 377 function submitActivateAddressBook() external 378 onlyAdmin(msg.sender) { 379 require(isActivated == false, "Already activated."); 380 require(adminList.length != 0, "No admin is listed."); 381 require(pocContractAddress != 0, "PoC contract is not registered."); 382 require(kirContractAddress != 0, "KIR contract is not registered."); 383 require(cnNodeIdList.length != 0, "No node ID is listed."); 384 require(cnNodeIdList.length == cnStakingContractList.length, "Invalid length between node IDs and staking contracts."); 385 require(cnStakingContractList.length == cnRewardAddressList.length, "Invalid length between staking contracts and reward addresses."); 386 387 bytes32 id = getId(Functions.ActivateAddressBook,0,0,0); 388 389 submitRequest(Functions.ActivateAddressBook,0,0,0); 390 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 391 executeRequest(id); 392 } 393 } 394 395 function submitUpdatePocContract(address _pocContractAddress, uint256 _version) external 396 notNull(_pocContractAddress) 397 onlyAdmin(msg.sender) { 398 require(PocContractInterface(_pocContractAddress).getPocVersion() == _version, "Invalid PoC version."); 399 400 bytes32 id = getId(Functions.UpdatePocContract,bytes32(_pocContractAddress),bytes32(_version),0); 401 402 submitRequest(Functions.UpdatePocContract,bytes32(_pocContractAddress),bytes32(_version),0); 403 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 404 executeRequest(id); 405 } 406 } 407 408 function submitUpdateKirContract(address _kirContractAddress, uint256 _version) external 409 notNull(_kirContractAddress) 410 onlyAdmin(msg.sender) { 411 require(KirContractInterface(_kirContractAddress).getKirVersion() == _version, "Invalid KIR version."); 412 413 bytes32 id = getId(Functions.UpdateKirContract,bytes32(_kirContractAddress),bytes32(_version),0); 414 415 submitRequest(Functions.UpdateKirContract,bytes32(_kirContractAddress),bytes32(_version),0); 416 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 417 executeRequest(id); 418 } 419 } 420 421 function submitUpdateSpareContract(address _spareContractAddress) external 422 onlyAdmin(msg.sender) { 423 bytes32 id = getId(Functions.UpdateSpareContract,bytes32(_spareContractAddress),0,0); 424 425 submitRequest(Functions.UpdateSpareContract,bytes32(_spareContractAddress),0,0); 426 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 427 executeRequest(id); 428 } 429 } 430 431 function submitRegisterCnStakingContract(address _cnNodeId, address _cnStakingContractAddress, address _cnRewardAddress) external 432 notNull(_cnNodeId) 433 notNull(_cnStakingContractAddress) 434 notNull(_cnRewardAddress) 435 onlyAdmin(msg.sender) { 436 if (cnNodeIdList.length > 0) { 437 require(cnNodeIdList[cnIndexMap[_cnNodeId]] != _cnNodeId, "CN node ID already exist."); 438 } 439 require(CnStakingContractInterface(_cnStakingContractAddress).nodeId() == _cnNodeId, "Invalid CN node ID."); 440 require(CnStakingContractInterface(_cnStakingContractAddress).rewardAddress() == _cnRewardAddress, "Invalid CN reward address."); 441 require(CnStakingContractInterface(_cnStakingContractAddress).isInitialized() == true, "CN contract is not initialized."); 442 443 bytes32 id = getId(Functions.RegisterCnStakingContract,bytes32(_cnNodeId),bytes32(_cnStakingContractAddress),bytes32(_cnRewardAddress)); 444 445 submitRequest(Functions.RegisterCnStakingContract,bytes32(_cnNodeId),bytes32(_cnStakingContractAddress),bytes32(_cnRewardAddress)); 446 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 447 executeRequest(id); 448 } 449 } 450 451 function submitUnregisterCnStakingContract(address _cnNodeId) external 452 notNull(_cnNodeId) 453 onlyAdmin(msg.sender) { 454 uint256 index = cnIndexMap[_cnNodeId]; 455 require(cnNodeIdList[index] == _cnNodeId, "Invalid CN node ID."); 456 require(cnNodeIdList.length > 1, "CN should be more than one."); 457 458 bytes32 id = getId(Functions.UnregisterCnStakingContract,bytes32(_cnNodeId),0,0); 459 460 submitRequest(Functions.UnregisterCnStakingContract,bytes32(_cnNodeId),0,0); 461 if(checkQuorum(id) && requestMap[id].state == RequestState.NotConfirmed) { 462 executeRequest(id); 463 } 464 } 465 466 /* 467 * Multisig functions 468 */ 469 function addAdmin(address _admin) external 470 onlyMultisigTx() 471 adminDoesNotExist(_admin) 472 validRequirement(adminList.length.add(1), requirement) { 473 isAdmin[_admin] = true; 474 adminList.push(_admin); 475 clearRequest(); 476 emit AddAdmin(_admin); 477 } 478 479 function deleteAdmin(address _admin) external 480 onlyMultisigTx() 481 onlyAdmin(_admin) 482 validRequirement(adminList.length.sub(1), requirement) { 483 uint256 adminCnt = adminList.length; 484 isAdmin[_admin] = false; 485 486 for (uint256 i=0; i < adminCnt - 1; i++) { 487 if (adminList[i] == _admin) { 488 adminList[i] = adminList[adminCnt - 1]; 489 break; 490 } 491 } 492 493 delete adminList[adminCnt - 1]; 494 adminList.length = adminList.length.sub(1); 495 clearRequest(); 496 emit DeleteAdmin(_admin); 497 } 498 499 function updateRequirement(uint256 _requirement) external 500 onlyMultisigTx() 501 validRequirement(adminList.length, _requirement) { 502 require(requirement != _requirement, "Same requirement."); 503 requirement = _requirement; 504 clearRequest(); 505 emit UpdateRequirement(_requirement); 506 } 507 508 function clearRequest() public 509 onlyMultisigTx() { 510 uint256 pendingRequestCnt = pendingRequestList.length; 511 512 for (uint256 i = 0; i < pendingRequestCnt; i++){ 513 delete requestMap[pendingRequestList[i]]; 514 } 515 delete pendingRequestList; 516 emit ClearRequest(); 517 } 518 519 function activateAddressBook() external 520 onlyMultisigTx() { 521 require(isActivated == false, "Already activated."); 522 require(adminList.length != 0, "No admin is listed."); 523 require(pocContractAddress != 0, "PoC contract is not registered."); 524 require(kirContractAddress != 0, "KIR contract is not registered."); 525 require(cnNodeIdList.length != 0, "No node ID is listed."); 526 require(cnNodeIdList.length == cnStakingContractList.length, "Invalid length between node IDs and staking contracts."); 527 require(cnStakingContractList.length == cnRewardAddressList.length, "Invalid length between staking contracts and reward addresses."); 528 isActivated = true; 529 530 emit ActivateAddressBook(); 531 } 532 533 function updatePocContract(address _pocContractAddress, uint256 _version) external 534 onlyMultisigTx() { 535 require(PocContractInterface(_pocContractAddress).getPocVersion() == _version, "Invalid PoC version."); 536 537 address prevPocContractAddress = pocContractAddress; 538 pocContractAddress = _pocContractAddress; 539 uint256 prevVersion = 0; 540 541 if(prevPocContractAddress != 0) { 542 prevVersion = PocContractInterface(prevPocContractAddress).getPocVersion(); 543 } 544 emit UpdatePocContract(prevPocContractAddress, prevVersion, _pocContractAddress, _version); 545 } 546 547 function updateKirContract(address _kirContractAddress, uint256 _version) external 548 onlyMultisigTx() { 549 require(KirContractInterface(_kirContractAddress).getKirVersion() == _version, "Invalid KIR version."); 550 551 address prevKirContractAddress = kirContractAddress; 552 kirContractAddress = _kirContractAddress; 553 uint256 prevVersion = 0; 554 555 if(prevKirContractAddress != 0) { 556 prevVersion = KirContractInterface(prevKirContractAddress).getKirVersion(); 557 } 558 emit UpdateKirContract(prevKirContractAddress, prevVersion, _kirContractAddress, _version); 559 } 560 561 function updateSpareContract(address _spareContractAddress) external 562 onlyMultisigTx() { 563 spareContractAddress = _spareContractAddress; 564 emit UpdateSpareContract(spareContractAddress); 565 } 566 567 function registerCnStakingContract(address _cnNodeId, address _cnStakingContractAddress, address _cnRewardAddress) external 568 onlyMultisigTx() { 569 if (cnNodeIdList.length > 0) { 570 require(cnNodeIdList[cnIndexMap[_cnNodeId]] != _cnNodeId, "CN node ID already exist."); 571 } 572 require(CnStakingContractInterface(_cnStakingContractAddress).nodeId() == _cnNodeId, "Invalid CN node ID."); 573 require(CnStakingContractInterface(_cnStakingContractAddress).rewardAddress() == _cnRewardAddress, "Invalid CN reward address."); 574 require(CnStakingContractInterface(_cnStakingContractAddress).isInitialized() == true, "CN contract is not initialized."); 575 576 uint256 index = cnNodeIdList.length; 577 cnIndexMap[_cnNodeId] = index; 578 cnNodeIdList.push(_cnNodeId); 579 cnStakingContractList.push(_cnStakingContractAddress); 580 cnRewardAddressList.push(_cnRewardAddress); 581 582 emit RegisterCnStakingContract(_cnNodeId, _cnStakingContractAddress, _cnRewardAddress); 583 } 584 585 function unregisterCnStakingContract(address _cnNodeId) external 586 onlyMultisigTx() { 587 uint256 index = cnIndexMap[_cnNodeId]; 588 require(cnNodeIdList[index] == _cnNodeId, "Invalid CN node ID."); 589 require(cnNodeIdList.length > 1, "CN should be more than one."); 590 591 if (index < cnNodeIdList.length - 1) { 592 cnNodeIdList[index] = cnNodeIdList[cnNodeIdList.length-1]; 593 cnStakingContractList[index] = cnStakingContractList[cnNodeIdList.length-1]; 594 cnRewardAddressList[index] = cnRewardAddressList[cnNodeIdList.length-1]; 595 596 cnIndexMap[cnNodeIdList[cnNodeIdList.length-1]] = index; 597 } 598 599 delete cnIndexMap[_cnNodeId]; 600 delete cnNodeIdList[cnNodeIdList.length-1]; 601 cnNodeIdList.length = cnNodeIdList.length.sub(1); 602 delete cnStakingContractList[cnStakingContractList.length-1]; 603 cnStakingContractList.length = cnStakingContractList.length.sub(1); 604 delete cnRewardAddressList[cnRewardAddressList.length-1]; 605 cnRewardAddressList.length = cnRewardAddressList.length.sub(1); 606 607 emit UnregisterCnStakingContract(_cnNodeId); 608 } 609 610 /* 611 * External function 612 */ 613 function reviseRewardAddress(address _rewardAddress) external 614 notNull(_rewardAddress) { 615 bool foundIt = false; 616 uint256 index = 0; 617 uint256 cnStakingContractListCnt = cnStakingContractList.length; 618 for(uint256 i = 0; i < cnStakingContractListCnt; i++){ 619 if (cnStakingContractList[i] == msg.sender) { 620 foundIt = true; 621 index = i; 622 break; 623 } 624 } 625 require(foundIt, "Msg.sender is not CN contract."); 626 address prevAddress = cnRewardAddressList[index]; 627 cnRewardAddressList[index] = _rewardAddress; 628 629 emit ReviseRewardAddress(cnNodeIdList[index], prevAddress, cnRewardAddressList[index]); 630 } 631 632 /* 633 * Getter functions 634 */ 635 function getState() external view returns(address[], uint256) { 636 return (adminList, requirement); 637 } 638 639 function getPendingRequestList() external view returns(bytes32[]) { 640 return pendingRequestList; 641 } 642 643 function getRequestInfo(bytes32 _id) external view returns(Functions,bytes32,bytes32,bytes32,address[],uint256,RequestState) { 644 return( 645 requestMap[_id].functionId, 646 requestMap[_id].firstArg, 647 requestMap[_id].secondArg, 648 requestMap[_id].thirdArg, 649 requestMap[_id].confirmers, 650 requestMap[_id].initialProposedTime, 651 requestMap[_id].state 652 ); 653 } 654 655 function getRequestInfoByArgs(Functions _functionId, bytes32 _firstArg, bytes32 _secondArg, bytes32 _thirdArg) external view returns(bytes32,address[],uint256,RequestState) { 656 bytes32 _id = getId(_functionId,_firstArg,_secondArg,_thirdArg); 657 return( 658 _id, 659 requestMap[_id].confirmers, 660 requestMap[_id].initialProposedTime, 661 requestMap[_id].state 662 ); 663 } 664 665 function getAllAddress() external view returns(uint8[], address[]) { 666 uint8[] memory typeList; 667 address[] memory addressList; 668 if(isActivated == false) { 669 typeList = new uint8[](0); 670 addressList = new address[](0); 671 } else { 672 typeList = new uint8[](cnNodeIdList.length * 3 + 2); 673 addressList = new address[](cnNodeIdList.length * 3 + 2); 674 uint256 cnNodeCnt = cnNodeIdList.length; 675 for (uint256 i = 0; i < cnNodeCnt; i ++){ 676 //add node id and its type number to array 677 typeList[i * 3] = uint8(CN_NODE_ID_TYPE); 678 addressList[i * 3] = address(cnNodeIdList[i]); 679 //add staking address and its type number to array 680 typeList[i * 3 + 1] = uint8(CN_STAKING_ADDRESS_TYPE); 681 addressList[i * 3 + 1] = address(cnStakingContractList[i]); 682 //add reward address and its type number to array 683 typeList[i * 3 + 2] = uint8(CN_REWARD_ADDRESS_TYPE); 684 addressList[i * 3 + 2] = address(cnRewardAddressList[i]); 685 } 686 typeList[cnNodeCnt *3] = uint8(POC_CONTRACT_TYPE); 687 addressList[cnNodeCnt * 3] = address(pocContractAddress); 688 typeList[cnNodeCnt * 3 + 1] = uint8(KIR_CONTRACT_TYPE); 689 addressList[cnNodeCnt * 3 + 1] = address(kirContractAddress); 690 } 691 return (typeList, addressList); 692 } 693 694 function getAllAddressInfo() external view returns(address[], address[], address[], address, address) { 695 return (cnNodeIdList, cnStakingContractList, cnRewardAddressList, pocContractAddress, kirContractAddress); 696 } 697 698 function getCnInfo(address _cnNodeId) external notNull(_cnNodeId) view returns(address, address, address) { 699 uint256 index = cnIndexMap[_cnNodeId]; 700 require(cnNodeIdList[index] == _cnNodeId, "Invalid CN node ID."); 701 return(cnNodeIdList[index], cnStakingContractList[index], cnRewardAddressList[index]); 702 } 703 } 704 705 interface CnStakingContractInterface { 706 function nodeId() external view returns(address); 707 function rewardAddress() external view returns(address); 708 function isInitialized() external view returns(bool); 709 } 710 interface PocContractInterface { 711 function getPocVersion() external pure returns(uint256); 712 } 713 interface KirContractInterface { 714 function getKirVersion() external pure returns(uint256); 715 }