| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- pragma solidity ^0.6.0;
- /**
- * @title CheckpointOracle
- * @author Gary Rong<garyrong@ethereum.org>, Martin Swende <martin.swende@ethereum.org>
- * @dev Implementation of the blockchain checkpoint registrar.
- */
- contract CheckpointOracle {
- /*
- Events
- */
- // NewCheckpointVote is emitted when a new checkpoint proposal receives a vote.
- event NewCheckpointVote(uint64 indexed index, bytes32 checkpointHash, uint8 v, bytes32 r, bytes32 s);
- /*
- Public Functions
- */
- constructor(address[] memory _adminlist, uint _sectionSize, uint _processConfirms, uint _threshold) public {
- for (uint i = 0; i < _adminlist.length; i++) {
- admins[_adminlist[i]] = true;
- adminList.push(_adminlist[i]);
- }
- sectionSize = _sectionSize;
- processConfirms = _processConfirms;
- threshold = _threshold;
- }
- /**
- * @dev Get latest stable checkpoint information.
- * @return section index
- * @return checkpoint hash
- * @return block height associated with checkpoint
- */
- function GetLatestCheckpoint()
- view
- public
- returns(uint64, bytes32, uint) {
- return (sectionIndex, hash, height);
- }
- // SetCheckpoint sets a new checkpoint. It accepts a list of signatures
- // @_recentNumber: a recent blocknumber, for replay protection
- // @_recentHash : the hash of `_recentNumber`
- // @_hash : the hash to set at _sectionIndex
- // @_sectionIndex : the section index to set
- // @v : the list of v-values
- // @r : the list or r-values
- // @s : the list of s-values
- function SetCheckpoint(
- uint _recentNumber,
- bytes32 _recentHash,
- bytes32 _hash,
- uint64 _sectionIndex,
- uint8[] memory v,
- bytes32[] memory r,
- bytes32[] memory s)
- public
- returns (bool)
- {
- // Ensure the sender is authorized.
- require(admins[msg.sender]);
- // These checks replay protection, so it cannot be replayed on forks,
- // accidentally or intentionally
- require(blockhash(_recentNumber) == _recentHash);
- // Ensure the batch of signatures are valid.
- require(v.length == r.length);
- require(v.length == s.length);
- // Filter out "future" checkpoint.
- if (block.number < (_sectionIndex+1)*sectionSize+processConfirms) {
- return false;
- }
- // Filter out "old" announcement
- if (_sectionIndex < sectionIndex) {
- return false;
- }
- // Filter out "stale" announcement
- if (_sectionIndex == sectionIndex && (_sectionIndex != 0 || height != 0)) {
- return false;
- }
- // Filter out "invalid" announcement
- if (_hash == ""){
- return false;
- }
- // EIP 191 style signatures
- //
- // Arguments when calculating hash to validate
- // 1: byte(0x19) - the initial 0x19 byte
- // 2: byte(0) - the version byte (data with intended validator)
- // 3: this - the validator address
- // -- Application specific data
- // 4 : checkpoint section_index(uint64)
- // 5 : checkpoint hash (bytes32)
- // hash = keccak256(checkpoint_index, section_head, cht_root, bloom_root)
- bytes32 signedHash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, _sectionIndex, _hash));
- address lastVoter = address(0);
- // In order for us not to have to maintain a mapping of who has already
- // voted, and we don't want to count a vote twice, the signatures must
- // be submitted in strict ordering.
- for (uint idx = 0; idx < v.length; idx++){
- address signer = ecrecover(signedHash, v[idx], r[idx], s[idx]);
- require(admins[signer]);
- require(uint256(signer) > uint256(lastVoter));
- lastVoter = signer;
- emit NewCheckpointVote(_sectionIndex, _hash, v[idx], r[idx], s[idx]);
- // Sufficient signatures present, update latest checkpoint.
- if (idx+1 >= threshold){
- hash = _hash;
- height = block.number;
- sectionIndex = _sectionIndex;
- return true;
- }
- }
- // We shouldn't wind up here, reverting un-emits the events
- revert();
- }
- /**
- * @dev Get all admin addresses
- * @return address list
- */
- function GetAllAdmin()
- public
- view
- returns(address[] memory)
- {
- address[] memory ret = new address[](adminList.length);
- for (uint i = 0; i < adminList.length; i++) {
- ret[i] = adminList[i];
- }
- return ret;
- }
- /*
- Fields
- */
- // A map of admin users who have the permission to update CHT and bloom Trie root
- mapping(address => bool) admins;
- // A list of admin users so that we can obtain all admin users.
- address[] adminList;
- // Latest stored section id
- uint64 sectionIndex;
- // The block height associated with latest registered checkpoint.
- uint height;
- // The hash of latest registered checkpoint.
- bytes32 hash;
- // The frequency for creating a checkpoint
- //
- // The default value should be the same as the checkpoint size(32768) in the ethereum.
- uint sectionSize;
- // The number of confirmations needed before a checkpoint can be registered.
- // We have to make sure the checkpoint registered will not be invalid due to
- // chain reorg.
- //
- // The default value should be the same as the checkpoint process confirmations(256)
- // in the ethereum.
- uint processConfirms;
- // The required signatures to finalize a stable checkpoint.
- uint threshold;
- }
|