|
| 1 | +// Copyright (c) 2016-2018 Clearmatics Technologies Ltd |
| 2 | +// SPDX-License-Identifier: LGPL-3.0+ |
| 3 | +pragma solidity ^0.4.23; |
| 4 | + |
| 5 | +import "./ECVerify.sol"; |
| 6 | + |
| 7 | +contract Validation { |
| 8 | + address Owner; |
| 9 | + |
| 10 | + event broadcastSig(address owner); |
| 11 | + event broadcastHashData(bytes header, bytes parentHash, bytes rootHash); |
| 12 | + event broadcastHash(bytes32 blockHash); |
| 13 | + |
| 14 | + address[] validators; |
| 15 | + |
| 16 | + /* |
| 17 | + * @param _validators list of validators at block 0 |
| 18 | + */ |
| 19 | + constructor (address[] _validators) public { |
| 20 | + Owner = msg.sender; |
| 21 | + for (uint i = 0; i < _validators.length; i++) { |
| 22 | + validators.push(_validators[i]); |
| 23 | + } |
| 24 | + } |
| 25 | + |
| 26 | + /* |
| 27 | + * |
| 28 | + */ |
| 29 | + function GetValidators() public view returns (address[] _validators) { |
| 30 | + return validators; |
| 31 | + } |
| 32 | + |
| 33 | + /* |
| 34 | + * @param header header rlp encoded, with extraData signatures removed |
| 35 | + * @param prefixHeader the new prefix for the signed hash header |
| 36 | + * @param prefixExtraData the new prefix for the extraData field |
| 37 | + */ |
| 38 | + function ValidateBlock(bytes header, bytes prefixHeader, bytes prefixExtraData) public { |
| 39 | + uint256 length = header.length; |
| 40 | + bytes32 blockHash = keccak256(header); |
| 41 | + |
| 42 | + emit broadcastHash(blockHash); |
| 43 | + |
| 44 | + bytes memory headerStart = new bytes(length - 141); |
| 45 | + bytes memory extraData = new bytes(31); |
| 46 | + bytes memory extraDataSig = new bytes(65); |
| 47 | + bytes memory headerEnd = new bytes(42); |
| 48 | + |
| 49 | + // Extract the start of the header and replace the length |
| 50 | + extractData(headerStart, header, 0, headerStart.length); |
| 51 | + assembly { |
| 52 | + let ret := staticcall(3000, 4, add(prefixHeader, 32), 2, add(headerStart, 33), 2) |
| 53 | + } |
| 54 | + |
| 55 | + // Extract the real extra data and create the signed hash |
| 56 | + extractData(extraData, header, length-140, extraData.length); |
| 57 | + assembly { |
| 58 | + let ret := staticcall(3000, 4, add(prefixExtraData, 32), 1, add(extraData, 32), 1) |
| 59 | + } |
| 60 | + |
| 61 | + // Extract the end of the header |
| 62 | + extractData(headerEnd, header, length-42, headerEnd.length); |
| 63 | + bytes memory newHeader = mergeHash(headerStart, extraData, headerEnd); |
| 64 | + |
| 65 | + bytes32 hashData = keccak256(newHeader); |
| 66 | + |
| 67 | + // Extract the signature of the hash create above |
| 68 | + extractData(extraDataSig, header, length-107, extraDataSig.length); |
| 69 | + |
| 70 | + address sig_addr = ECVerify.ecrecovery(hashData, extraDataSig); |
| 71 | + |
| 72 | + emit broadcastSig(sig_addr); |
| 73 | + |
| 74 | + } |
| 75 | + |
| 76 | + function mergeHash(bytes headerStart, bytes extraData, bytes headerEnd) internal view returns (bytes output) { |
| 77 | + // Get the lengths sorted because they're needed later... |
| 78 | + uint256 headerStartLength = headerStart.length; |
| 79 | + uint256 extraDataLength = extraData.length; |
| 80 | + uint256 extraDataStart = headerStartLength + 32; |
| 81 | + uint256 headerEndLength = headerEnd.length; |
| 82 | + uint256 headerEndStart = extraDataLength + headerStartLength + 32 + 2; |
| 83 | + uint256 newLength = headerStartLength + extraDataLength + headerEndLength + 2; // extra two is for the prefix |
| 84 | + bytes memory header = new bytes(newLength); |
| 85 | + |
| 86 | + |
| 87 | + // Add in the first part of the header |
| 88 | + assembly { |
| 89 | + let ret := staticcall(3000, 4, add(headerStart, 32), headerStartLength, add(header, 32), headerStartLength) |
| 90 | + } |
| 91 | + assembly { |
| 92 | + let ret := staticcall(3000, 4, add(extraData, 32), extraDataLength, add(header, extraDataStart), extraDataLength) |
| 93 | + } |
| 94 | + assembly { |
| 95 | + let ret := staticcall(3000, 4, add(headerEnd, 32), headerEndLength, add(header, headerEndStart), headerEndLength) |
| 96 | + } |
| 97 | + |
| 98 | + output = header; |
| 99 | + } |
| 100 | + |
| 101 | + /* |
| 102 | + * @param data memory allocation for the data you need to extract |
| 103 | + * @param sig array from which the data should be extracted |
| 104 | + * @param start index which the data starts within the byte array |
| 105 | + * @param length total length of the data to be extracted |
| 106 | + */ |
| 107 | + function extractData(bytes data, bytes input, uint start, uint length) private pure { |
| 108 | + for (uint i=0; i<length; i++) { |
| 109 | + data[i] = input[start+i]; |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | +} |
0 commit comments