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 }