* all: implement simple checkpoint syncing cmd, les, node: remove callback mechanism cmd, node: remove callback definition les: simplify the registrar les: expose checkpoint rpc services in the light client les, light: don't store untrusted receipt cmd, contracts, les: discard stale checkpoint cmd, contracts/registrar: loose restriction of registeration cmd, contracts: add replay-protection all: off-chain multi-signature contract params: deploy checkpoint contract for rinkeby cmd/registrar: add raw signing mode for registrar cmd/registrar, contracts/registrar, les: fixed messages * cmd/registrar, contracts/registrar: fix lints * accounts/abi/bind, les: address comments * cmd, contracts, les, light, params: minor checkpoint sync cleanups * cmd, eth, les, light: move checkpoint config to config file * cmd, eth, les, params: address comments * eth, les, params: address comments * cmd: polish up the checkpoint admin CLI * cmd, contracts, params: deploy new version contract * cmd/checkpoint-admin: add another flag for clef mode signing * cmd, contracts, les: rename and regen checkpoint oracle with abigen
		
			
				
	
	
		
			175 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
pragma solidity ^0.5.10;
 | 
						|
 | 
						|
/**
 | 
						|
 * @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;
 | 
						|
}
 |