A principled approach to bridges

https://ethresear.ch/t/a-principled-approach-to-bridges/14725/3

I actually think that governance can be completely eliminated in this system, which seems preferable. The core assumption that leads this to require governance is that this system must be able to decide what the canonical block header is for any past block on any given chain. But I think that is beyond the scope of what this contract needs to do.

Rather than having some governance mechanism mandated with curating oracles and conflict resolution, in order to decide the header for each historical block, all this system needs to do is aggregate the block headers reported by any number of header oracles. It should simply be a common interface for querying the block header reported by many disparate mechanisms.

I see no reason why anyone should not be able to add an adapter to any header oracle and it simply be up to the user (the person / contract / app consuming block headers) to decide what combination of oracles to trust and what the conflict resolution rules / mechanism should be.

Perhaps the contract should provide an optional conflict resolution mechanism, analogous to an M/N multisig, where the user would require M/N of their chosen headers to agree on the header for any given block in order to consider the reported header valid.

From the user’s perspective, here is an interface that feels sufficient.

interface metaHeaderOracle {
  /// @dev Returns the block header reported by a given oracle for a given block.
  /// @param oracleAdapter Address of the oracle adapter to query.
  /// @param blockNumber Block number for which to return a header.
  /// @return blockHeader Block header reported by the given oracle adapter for the given block number.
  function getHeaderFromOracle(
    address oracleAdapter,
    uint256 blockNumber)
  public view returns(bytes32 blockHeader);
    
  /// @dev Returns the block headers for a given block reported by a given set of oracles.
  /// @param oracleAdapters Array of address for the oracle adapters to query, MUST be provided in numerical order from smallest to largest.
  /// @param blockNumber Block number for which to return headers.
  /// @return blockHeaders Array of block header reported by the given oracle adapters for the given block number.
  /// @notice This method MUST revert if the oracleAdapters array contains duplicates.
  function getHeadersFromOracles(
    address[] oracleAdapters,
    unint256 blockNumber)
  public view returns(bytes32[] blockHeaders);
    
  /// @dev Returns the blockheader agreed upon by a threshold of given header oracles.
  /// @param oracleAdapters Array of address for the oracle adapters to query, MUST be provided in numerical order from smallest to largest.
  /// @param blockNumber Block number for which to return headers.
  /// @param threshold Threshold of oracles that must report the same header for the given block. `threshold` MUST be `<= oracleAdapters.length && > oracleAdapters.length / 2`.
  /// @return blockHeader Block header reported by the required threshold of given oracle adapters for the given block number.
  /// @notice This method MUST revert if the oracleAdapters array contains duplicates.
  function getHeaderFromThreshold(
    address[] oracleAdapters,
    unint256 blockNumber,
    uint256 threshold)
  public view returns(bytes32 blockHeader);
}