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  }