github.com/codingfuture/orig-energi3@v0.8.4/energi/contracts/src/CheckpointRegistryV1.sol (about)

     1  // Copyright 2019 The Energi Core Authors
     2  // This file is part of Energi Core.
     3  //
     4  // Energi Core is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU 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  // Energi Core 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 General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Energi Governance system is the fundamental part of Energi Core.
    18  
    19  // NOTE: It's not allowed to change the compiler due to byte-to-byte
    20  //       match requirement.
    21  pragma solidity 0.5.16;
    22  //pragma experimental SMTChecker;
    23  pragma experimental ABIEncoderV2;
    24  
    25  import { IGovernedContract, GovernedContract } from "./GovernedContract.sol";
    26  import { IGovernedProxy } from "./IGovernedProxy.sol";
    27  import { IMasternodeRegistry } from "./IMasternodeRegistry.sol";
    28  import { ICheckpoint } from "./ICheckpoint.sol";
    29  import { ICheckpointRegistry } from "./ICheckpointRegistry.sol";
    30  import { StorageBase }  from "./StorageBase.sol";
    31  
    32  /**
    33   * Permanent storage of Checkpoint Registry V1 data.
    34   */
    35  // solium-disable-next-line no-empty-blocks
    36  contract StorageCheckpointRegistryV1 is
    37      StorageBase
    38  {
    39      // NOTE: ABIEncoderV2 is not acceptable at the moment of development!
    40  
    41      ICheckpoint[] public checkpoints;
    42  
    43      function add(ICheckpoint cp)
    44          external
    45          requireOwner
    46      {
    47          checkpoints.push(cp);
    48      }
    49  
    50      function listCheckpoints()
    51          external view
    52          returns(ICheckpoint[] memory res)
    53      {
    54          uint len = checkpoints.length;
    55          res = new ICheckpoint[](len);
    56          for (uint i = len; i-- > 0;) {
    57              res[i] = checkpoints[i];
    58          }
    59      }
    60  }
    61  
    62  /**
    63   * Checkpoint object
    64   */
    65  contract CheckpointV1 is ICheckpoint {
    66      uint constant internal SIGNING_PERIOD = 24 * 60;
    67  
    68      IGovernedProxy internal mnregistry_proxy;
    69      uint internal since;
    70  
    71      uint internal number;
    72      bytes32 internal hash;
    73      bytes32 public signatureBase;
    74      mapping(address => uint) internal signers;
    75  
    76      bytes[] internal signature_list;
    77  
    78      constructor(IGovernedProxy _mnregistry_proxy, uint _number, bytes32 _hash, bytes32 _sigbase) public {
    79          mnregistry_proxy = _mnregistry_proxy;
    80          since = block.number;
    81          number = _number;
    82          hash = _hash;
    83          signatureBase = _sigbase;
    84      }
    85  
    86      function info() external view returns(uint, bytes32, uint) {
    87          return(number, hash, since);
    88      }
    89  
    90      function sign(bytes calldata signature) external {
    91          require((block.number - since) < SIGNING_PERIOD, "Signing has ended");
    92  
    93          require(signature.length == 65, "Invalid signature length");
    94          (bytes32 r, bytes32 s) = abi.decode(signature, (bytes32, bytes32));
    95          address masternode = ecrecover(signatureBase, uint8(signature[64]), r, s);
    96  
    97          require(signers[masternode] == 0, "Already signed");
    98  
    99          IMasternodeRegistry registry = IMasternodeRegistry(address(mnregistry_proxy.impl()));
   100          require(registry.isActive(masternode), "Not active MN");
   101  
   102          signature_list.push(signature);
   103          signers[masternode] = signature_list.length;
   104      }
   105  
   106      function signature(address masternode) external view returns(bytes memory){
   107          uint index = signers[masternode];
   108          require(index != 0, "Not signed yet");
   109          return signature_list[index - 1];
   110      }
   111  
   112      function signatures() external view returns(bytes[] memory siglist){
   113          uint len = signature_list.length;
   114          siglist = new bytes[](len);
   115          for (uint i = len; i-- > 0;) {
   116              siglist[i] = signature_list[i];
   117          }
   118      }
   119  }
   120  
   121  /**
   122   * Genesis hardcoded version of CheckpointRegistry
   123   *
   124   * NOTE: it MUST NOT change after blockchain launch!
   125   */
   126  contract CheckpointRegistryV1 is
   127      GovernedContract,
   128      ICheckpointRegistry
   129  {
   130      // Data for migration
   131      //---------------------------------
   132      StorageCheckpointRegistryV1 public v1storage;
   133      IGovernedProxy public mnregistry_proxy;
   134      address public CPP_signer;
   135      //---------------------------------
   136  
   137      constructor(address _proxy, IGovernedProxy _mnregistry_proxy, address _cpp_signer)
   138          public GovernedContract(_proxy)
   139      {
   140          v1storage = new StorageCheckpointRegistryV1();
   141          mnregistry_proxy = _mnregistry_proxy;
   142          CPP_signer = _cpp_signer;
   143      }
   144  
   145      // IGovernedContract
   146      //---------------------------------
   147      function _destroy(IGovernedContract _newImpl) internal {
   148          v1storage.setOwner(_newImpl);
   149      }
   150  
   151      // ICheckpointRegistry
   152      //---------------------------------
   153      function signatureBase(uint number, bytes32 hash)
   154          public view
   155          returns(bytes32 sigbase)
   156      {
   157          sigbase = keccak256(
   158              abi.encodePacked(
   159                  "||Energi Blockchain Checkpoint||",
   160                  number,
   161                  hash
   162              )
   163          );
   164      }
   165  
   166      function propose(uint number, bytes32 hash, bytes calldata signature) external returns(ICheckpoint checkpoint) {
   167          // Allow to propose by any caller as far as signature is correct.
   168          // This leaves us possibility of automatic checkpoint creation.
   169          //require(_callerAddress() == CPP_signer, "Invalid caller");
   170  
   171          bytes32 sigbase = signatureBase(number, hash);
   172          require(signature.length == 65, "Invalid signature length");
   173          (bytes32 r, bytes32 s) = abi.decode(signature, (bytes32, bytes32));
   174          require(ecrecover(sigbase, uint8(signature[64]), r, s) == CPP_signer, "Invalid signer");
   175  
   176          checkpoint = new CheckpointV1(mnregistry_proxy, number, hash, sigbase);
   177          v1storage.add(checkpoint);
   178  
   179          emit Checkpoint(
   180              number,
   181              hash,
   182              checkpoint
   183          );
   184      }
   185  
   186      function checkpoints() external view returns(ICheckpoint[] memory) {
   187          return v1storage.listCheckpoints();
   188      }
   189  
   190      function sign(ICheckpoint checkpoint, bytes calldata signature) external {
   191          checkpoint.sign(signature);
   192      }
   193  
   194      // Safety
   195      //---------------------------------
   196      function () external payable {
   197          revert("Not supported");
   198      }
   199  }