pragma solidity ^0.5.10; /** @title TestnetRelay */ /** @author Summa (https://summa.one) */ import {OnDemandSPV} from "./OnDemandSPV.sol"; contract TestnetRelay is OnDemandSPV { constructor( bytes memory _genesisHeader, uint256 _height, bytes32 _periodStart, uint256 _firstID ) OnDemandSPV( _genesisHeader, _height, _periodStart, _firstID ) public {return ;} function _addHeadersWithRetarget( bytes memory, // _oldPeriodStartHeader, bytes memory _oldPeriodEndHeader, bytes memory _headers ) internal returns (bool) { return _addHeaders(_oldPeriodEndHeader, _headers); } function _addHeaders(bytes memory _anchor, bytes memory _headers, bool) internal returns (bool) { return _addHeaders(_anchor, _headers); } /// @notice Adds headers to storage after validating /// @dev We check integrity and consistency of the header chain /// @param _anchor The header immediately preceeding the new chain /// @param _headers A tightly-packed list of new 80-byte Bitcoin headers to record /// @return True if successfully written, error otherwise function _addHeaders(bytes memory _anchor, bytes memory _headers) internal returns (bool) { uint256 _height; bytes memory _header; bytes32 _currentDigest; bytes32 _previousDigest = _anchor.hash256(); /* uint256 _target = _headers.slice(0, 80).extractTarget(); */ uint256 _anchorHeight = _findHeight(_previousDigest); /* NB: errors if unknown */ /* require( _internal || _anchor.extractTarget() == _target, "Unexpected retarget on external call"); */ require(_headers.length % 80 == 0, "Header array length must be divisible by 80"); /* NB: 1. check that the header has sufficient work 2. check that headers are in a coherent chain (no retargets, hash links good) 3. Store the block connection 4. Store the height */ for (uint256 i = 0; i < _headers.length / 80; i = i.add(1)) { _header = _headers.slice(i.mul(80), 80); _height = _anchorHeight.add(i + 1); _currentDigest = _header.hash256(); /* NB: if the block is already authenticated, we don't need to a work check Or write anything to state. This saves gas */ if (previousBlock[_currentDigest] == bytes32(0)) { require( abi.encodePacked(_currentDigest).reverseEndianness().bytesToUint() <= _header.extractTarget(), "Header work is insufficient"); previousBlock[_currentDigest] = _previousDigest; if (_height % HEIGHT_INTERVAL == 0) { /* NB: We store the height only every 4th header to save gas */ blockHeight[_currentDigest] = _height; } } /* NB: we do still need to make chain level checks tho */ /* require(_header.extractTarget() == _target, "Target changed unexpectedly"); */ require(_header.validateHeaderPrevHash(_previousDigest), "Headers do not form a consistent chain"); _previousDigest = _currentDigest; } emit Extension( _anchor.hash256(), _currentDigest); return true; } }