* 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;
 | |
| }
 |