System Contracts

System contracts are the Energy Web Chain's smart contracts that implement OpenEthereum's protocols for Aura Proof-of-Authority consensus mechanism.

Energy Web's smart contracts are open-sourced, and you can see them on github here.

Implementing Client Protocol

System contracts are the Energy Web Chain’s smart contracts that implement OpenEthereum’s permissioning protocols. These protocols determine what actions can be taken on the network.

In order to adhere to the expected protocol, the Energy Web Chain’s system contracts must implement the interfaces that are expected by the AuRa consensus engine, so that it can conform to the client’s protocols.

Let’s take OpenEthereum's Validator-Set contract as an example.

The OpenEthereum documentation specifies that “A simple validator contract has to have the following interface”

[
    {
        "constant": false,
        "inputs": [],
        "name": "finalizeChange",
        "outputs": [],
        "payable": false,
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "getValidators",
        "outputs": [
            {
                "name": "_validators",
                "type": "address[]"
            }
        ],
        "payable": false,
        "type": "function"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "name": "_parent_hash",
                "type": "bytes32"
            },
            {
                "indexed": false,
                "name": "_new_set",
                "type": "address[]"
            }
        ],
        "name": "InitiateChange",
        "type": "event"
    }
]

Now let’s look at Energy Web’s ValidatorSetRelay smart contract.

You can see that this smart contract implements all of the functions of the Validator-Set protocol interface that was specified above.

pragma solidity 0.5.8;

import "../misc/Ownable.sol";
import "../interfaces/IValidatorSetRelay.sol";
import "../interfaces/IValidatorSet.sol";
import "../interfaces/IValidatorSetRelayed.sol";


/// @title Validator Set Relay contract
/// @notice This owned contract is present in the chainspec file. The Relay contract
/// relays the function calls to a logic contract called Relayed for upgradeability
contract ValidatorSetRelay is IValidatorSet, IValidatorSetRelay, Ownable {

    /// System address, used by the block sealer
    /// Not constant cause it is changed for testing
    address public systemAddress = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE;
    
    /// Address of the inner validator set contract
    IValidatorSetRelayed public relayedSet;

    /// Emitted in case a new Relayed contract is set
    event NewRelayed(address indexed old, address indexed current);

    modifier nonDefaultAddress(address _address) {
        require(_address != address(0), "Address cannot be 0x0");
        _;
    }

    modifier onlySystem() {
        require(msg.sender == systemAddress, "Sender is not system");
        _;
    }

    modifier onlyRelayed() {
        require(msg.sender == address(relayedSet), "Sender is not the Relayed contract");
        _;
    }

    constructor(address _owner, address _relayedSet)
        public
    {
        _transferOwnership(_owner);
        _setRelayed(_relayedSet);
    }

    /// @notice This function is used by the Relayed logic contract
    /// to iniate a change in the active validator set
    /// @dev emits `InitiateChange` which is listened by the Parity client
    /// @param _parentHash Blockhash of the parent block
    /// @param _newSet List of addresses of the desired active validator set
    /// @return True if event was emitted
    function callbackInitiateChange(bytes32 _parentHash, address[] calldata _newSet)
        external
        onlyRelayed
        returns (bool)
    {
        emit InitiateChange(_parentHash, _newSet);
        return true;
    }

    /// @notice Finalizes changes of the active validator set.
    /// Called by SYSTEM
    function finalizeChange()
        external
        onlySystem
    {
        relayedSet.finalizeChange();
    }

    /// @notice This function is used by validators to submit Benign reports
    /// on other validators. Can only be called by the validator who submits
    /// the report
    /// @dev emits `ReportedBenign` event in the Relayed logic contract
    /// @param _validator The validator to report
    /// @param _blockNumber The blocknumber to report on
    function reportBenign(address _validator, uint256 _blockNumber)
        external
    {
        relayedSet.reportBenign(
            msg.sender,
            _validator,
            _blockNumber
        );
    }

    /// @notice This function is used by validators to submit Malicious reports
    /// on other validators. Can only be called by the validator who submits
    /// the report
    /// @dev emits `ReportedMalicious` event in the Relayed logic contract
    /// @param _validator The validator to report
    /// @param _blockNumber The blocknumber to report on
    /// @param _proof Proof to submit. Right now it is not used for anything
    function reportMalicious(address _validator, uint256 _blockNumber, bytes calldata _proof)
        external
    {
        relayedSet.reportMalicious(
            msg.sender,
            _validator,
            _blockNumber,
            _proof
        );
    }

    /// @notice Sets the Relayed logic contract address. Only callable by the owner.
    /// The address is assumed to belong to a contract that implements the
    /// `IValidatorSetRelayed` interface
    /// @param _relayedSet The contract address
    function setRelayed(address _relayedSet)
        external
        onlyOwner
    {
        _setRelayed(_relayedSet);
    }

    /// @notice Returns the currently active validators
    /// @return The list of addresses of currently active validators
    function getValidators()
        external
        view
        returns (address[] memory)
    {
        return relayedSet.getValidators();
    }

    /// @dev The actual logic of setting the Relayed contract
    function _setRelayed(address _relayedSet)
        private
        nonDefaultAddress(_relayedSet)
    {
        require(
            _relayedSet != address(relayedSet),
            "New relayed contract address cannot be the same as the current one"
        );
        address oldRelayed = address(relayedSet);
        relayedSet = IValidatorSetRelayed(_relayedSet);
        emit NewRelayed(oldRelayed, _relayedSet);
    }
}

Last updated