Contract 0x2531d9b08430250a7183d7af11913f47090ff4db

Contract Overview

Balance:
0 DEV
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x6291db9d1912abcefe72c3a5d79d2d3590e1de50acde16564080d586977fed030x6080604033481902022-12-13 13:25:1849 days 16 hrs ago0xfaae07bac050bee1efc1a589be6629c3775f3272 IN  Create: ProofChain0 DEV0.005115138
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x76459fc95a0aba318892334db008efbee235508b21618d679c547cfbd740d69a36584332023-02-01 6:12:4211 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x76459fc95a0aba318892334db008efbee235508b21618d679c547cfbd740d69a36584332023-02-01 6:12:4211 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0x0f641dc740ff3d40404f57efd72123e5125d572f9058426c38d70b96a2a775e736581402023-02-01 5:12:181 hr 11 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x0f641dc740ff3d40404f57efd72123e5125d572f9058426c38d70b96a2a775e736581402023-02-01 5:12:181 hr 11 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0xe9ddd4987442b221712b53ed6d0988023eae88a50ca7b025dfaa7dcb8bf4b61636578442023-02-01 4:11:482 hrs 11 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xe9ddd4987442b221712b53ed6d0988023eae88a50ca7b025dfaa7dcb8bf4b61636578442023-02-01 4:11:482 hrs 11 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0xf08eb223a412cbf80389841179adfece60500f4617f3fb0e876d66782c13e27136575522023-02-01 3:11:303 hrs 12 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xf08eb223a412cbf80389841179adfece60500f4617f3fb0e876d66782c13e27136575522023-02-01 3:11:303 hrs 12 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0x60ce21ccd3df551961398c7ca82a50eb76b4687613b7ec7fb0821c1354c6164d36572552023-02-01 2:11:184 hrs 12 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x60ce21ccd3df551961398c7ca82a50eb76b4687613b7ec7fb0821c1354c6164d36572552023-02-01 2:11:184 hrs 12 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0xd7484985b06c7969f515514180a93f354cea90c347abec27e1ef3af8414a8a4e36569622023-02-01 1:11:005 hrs 12 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xd7484985b06c7969f515514180a93f354cea90c347abec27e1ef3af8414a8a4e36569622023-02-01 1:11:005 hrs 12 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0x2962d82fca0c3060590b507943efa6ca9f6cd37e34f0b9b905637bf0ce13f49f36566652023-02-01 0:10:486 hrs 12 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x2962d82fca0c3060590b507943efa6ca9f6cd37e34f0b9b905637bf0ce13f49f36566652023-02-01 0:10:486 hrs 12 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0xf0bf2d6601924d89c8b6e74a1e80a224271ca26b5ff8b823b5c0ed72b2ca707136563812023-01-31 23:10:547 hrs 12 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xf0bf2d6601924d89c8b6e74a1e80a224271ca26b5ff8b823b5c0ed72b2ca707136563812023-01-31 23:10:547 hrs 12 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0xc486ace4bccba6c5e12419e5742e6bc7827fc7b274fe022f39eeb0b98465070836561252023-01-31 22:10:488 hrs 12 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0x87ceb5a9c9cc533c273d1307febd154f3129982c7b36f23175ab3cd309abe75336561252023-01-31 22:10:488 hrs 12 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x87ceb5a9c9cc533c273d1307febd154f3129982c7b36f23175ab3cd309abe75336561252023-01-31 22:10:488 hrs 12 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0xe723aef831de15b7e82470c2654abba781165d404ffa3d6c3e2c0b3da7ad7f5f36558752023-01-31 21:09:129 hrs 14 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xe723aef831de15b7e82470c2654abba781165d404ffa3d6c3e2c0b3da7ad7f5f36558752023-01-31 21:09:129 hrs 14 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0x3557c7347483b83185a8966f4b20bb21c1a325f8ef6b97cb10b8edc0617cc2d136555992023-01-31 20:09:0610 hrs 14 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x3557c7347483b83185a8966f4b20bb21c1a325f8ef6b97cb10b8edc0617cc2d136555992023-01-31 20:09:0610 hrs 14 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
0xf259c3d15477dd241efbf58dfa3fbef13ce2651ffbb5bac7df92d8fab887ce8236554152023-01-31 19:31:1810 hrs 52 mins ago 0x2531d9b08430250a7183d7af11913f47090ff4db0x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xf259c3d15477dd241efbf58dfa3fbef13ce2651ffbb5bac7df92d8fab887ce8236554152023-01-31 19:31:1810 hrs 52 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x2531d9b08430250a7183d7af11913f47090ff4db0 DEV
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ProofChain

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 7 : ProofChain.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "./IOperationalStaking.sol";
import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract ProofChain is OwnableUpgradeable {
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set;

    IOperationalStaking _stakingInterface; // staking contract

    bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE");
    bytes32 public constant BLOCK_SPECIMEN_PRODUCER_ROLE = keccak256("BLOCK_SPECIMEN_PRODUCER_ROLE");
    bytes32 public constant AUDITOR_ROLE = keccak256("AUDITOR_ROLE");
    uint256 private constant _DIVIDER = 10**18; // 18 decimals used for scaling

    uint256 private _blockSpecimenQuorum; // The value is represented as a uint <= 10**18. The threshold value will later be divided by 10**18 to represent it as a percentage.  e.g.) 10**18 == 100%; 5 * 10**17 == 50%;
    uint256 private _secondsPerBlock; // average block time on the chain where the ProofChain is deployed
    uint128 private _blockSpecimenRewardAllocation; // the reward allocated per block hash
    uint128 private _bspRequiredStake; // how much a validator should have staked in order to run an operator
    uint64 private _blockSpecimenSessionDuration; // the length of a session in blocks
    uint64 private _minSubmissionsRequired; // min number of participants who submitted the agreed specimen hash in order for the quorum to be achieved

    EnumerableSetUpgradeable.Bytes32Set private _roleNames; // set of all role names, this is unused anymore

    EnumerableSetUpgradeable.AddressSet private _blockSpecimenProducers; // currently enabled block specimen producer operators
    EnumerableSetUpgradeable.AddressSet private _governors; // governor operators
    EnumerableSetUpgradeable.AddressSet private _auditors; // auditor operators

    mapping(address => uint128) public validatorIDs; // maps an operator address to validatorId
    mapping(uint128 => EnumerableSetUpgradeable.AddressSet) private _validatorOperators; // operator addresses that validator owns
    mapping(address => bytes32) public operatorRoles; // operator address => role
    mapping(uint128 => uint128) private _validatorActiveOperatorsCounters; // how many operators are enabled per validator given validator id
    mapping(uint64 => mapping(uint64 => BlockSpecimenSession)) private _sessions; // chainId => blockHeight
    mapping(uint64 => ChainData) private _chainData; // by chain id

    EnumerableSetUpgradeable.AddressSet private _blockResultProducers; // currently enabled block result producer operators
    mapping(uint64 => mapping(uint64 => BlockSpecimenSession)) private _blockResultSessions; // chainId => blockHeight
    bytes32 public constant BLOCK_RESULT_PRODUCER_ROLE = keccak256("BLOCK_RESULT_PRODUCER_ROLE");
    uint128 private _brpRequiredStake; // how much a validator should have staked in order to run an operator
    uint128 private _blockResultRewardAllocation; // the reward allocated per block hash

    mapping(bytes32 => string[]) private _urls; // hash => urls

    struct ChainData {
        uint256 blockOnTargetChain; // block number on the chain for which BSP are produced which is mapped to the current chain block
        uint256 blockOnCurrentChain; // block number on the chain where the ProofChain is deployed. it is mapped to the target chain block
        uint256 secondsPerBlock; // average block time on the chain for which BSP is generated
        uint128 allowedThreshold; // block offsett threshold, used to handle minor de-synchronization over time
        uint128 maxSubmissionsPerBlockHeight; // max number of block hashes allowed to submit per block height
        uint64 nthBlock; // block divisor
    }

    struct BlockHash {
        mapping(bytes32 => address[]) participants; // specimen hash => operators who submitted the specimen hash
        bytes32[] specimenHashes; // raw specimen hashes
    }

    struct SessionParticipantData {
        uint128 stake; // stake at the time when an operator submitted the first specimen hash
        uint128 submissionCounter; // how many specimen hashes an operator has submitted
    }

    struct BlockSpecimenSession {
        mapping(bytes32 => BlockHash) blockHashes;
        bytes32[] blockHashesRaw;
        mapping(address => SessionParticipantData) participantsData; // stake and submission counter, pack these together to save gas
        uint64 sessionDeadline; // the last block when an operator can submit a specimen hash
        bool requiresAudit; // auditor can arbitrate the session only if this is set to true
    }

    event OperatorAdded(address operator, uint128 validatorId, bytes32 role);

    event OperatorRemoved(address operator);

    event OperatorEnabled(address operator);

    event OperatorDisabled(address operator);

    event BlockSpecimenProductionProofSubmitted(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 specimenHash, // SHA-256 content-hash of specimen object file;
        string storageURL, // URL of specimen storage
        uint128 submittedStake
    );

    event SessionStarted(uint64 indexed chainId, uint64 indexed blockHeight, uint64 deadline);

    event BlockSpecimenRewardAwarded(uint64 indexed chainId, uint64 indexed blockHeight, bytes32 indexed blockhash, bytes32 specimenhash);

    event BlockResultRewardAwarded(uint64 indexed chainId, uint64 indexed blockHeight, bytes32 indexed specimenHash, bytes32 blockResultHash);

    event BSPQuorumNotReached(uint64 indexed chainId, uint64 blockHeight);

    event BRPQuorumNotReached(uint64 indexed chainId, uint64 blockHeight);

    event BlockSpecimenRewardChanged(uint128 newBlockSpecimenRewardAllocation);

    event MinimumRequiredStakeChanged(uint128 newStakeRequirement);

    event StakingInterfaceChanged(address newInterfaceAddress);

    event SpecimenSessionQuorumChanged(uint256 newQuorumThreshold);

    event SpecimenSessionDurationChanged(uint64 newSessionDuration);

    event SpecimenSessionMinSubmissionChanged(uint64 minSubmissions);

    event NthBlockChanged(uint64 indexed chainId, uint64 indexed nthBlock);

    event MaxSubmissionsPerBlockHeightChanged(uint256 maxSubmissions);

    event ChainSyncDataChanged(uint64 indexed chainId, uint256 blockOnTargetChain, uint256 blockOnCurrentChain, uint256 secondsPerBlock);

    event SecondsPerBlockChanged(uint64 indexed secondsPerBlock);

    event BlockHeightSubmissionThresholdChanged(uint64 indexed chainId, uint64 threshold);

    event MinimumRequiredBlockResultStakeChanged(uint128 newStakeRequirement);

    event BlockResultProductionProofSubmitted(uint64 chainId, uint64 blockHeight, bytes32 specimenHash, bytes32 resultHash, string storageURL, uint128 submittedStake);

    event BlockResultSessionQuorumChanged(uint256 newQuorumThreshold);

    event BlockSpecimenResultChanged(uint128 newBlockResultRewardAllocation);

    event BlockResultRewardChanged(uint128 newBlockSpecimenRewardAllocation);

    modifier onlyGovernor() {
        require(_governors.contains(msg.sender), "Sender is not GOVERNANCE_ROLE");
        _;
    }

    /**
     * Operators will have multiple addresses: the address they submit the proofs from and the address that manages staking and operator instances
     */
    modifier onlyOperatorManager(address operator) {
        (address validatorAddress, , , ) = _stakingInterface.getValidatorMetadata(validatorIDs[operator]);
        require(validatorAddress == msg.sender, "Sender is not operator manager");
        _;
    }

    function initialize(address initialOwner, address stakingContract) public initializer {
        __Ownable_init();

        _governors.add(msg.sender);

        _roleNames.add(GOVERNANCE_ROLE);
        _roleNames.add(BLOCK_SPECIMEN_PRODUCER_ROLE);
        _roleNames.add(AUDITOR_ROLE);

        setQuorumThreshold(_DIVIDER / 2); // 50%
        setBlockSpecimenReward(10**14); // 0.0001
        setSessionDuration(240); // blocks
        setMinSubmissionsRequired(2);
        setStakingInterface(stakingContract);
        _governors.remove(msg.sender);

        operatorRoles[initialOwner] = GOVERNANCE_ROLE;
        _governors.add(initialOwner);
        emit OperatorAdded(initialOwner, 0, GOVERNANCE_ROLE);
    }

    /**
     * Adds operator on the staking contract
     */
    function addValidator(address validator, uint128 commissionRate) external onlyGovernor {
        _stakingInterface.addValidator(validator, commissionRate);
    }

    /**
     * Disables the given operator on the staking contract
     */
    function disableValidator(uint128 validatorId, uint256 blockNumber) external onlyGovernor {
        _stakingInterface.disableValidator(validatorId, blockNumber);
    }

    /**
     * Enables the operator instance. The operators need to call that function before they can start submitting proofs
     */
    function enableBSPOperator(address operator) external onlyOperatorManager(operator) {
        _enableOperator(operator, BLOCK_SPECIMEN_PRODUCER_ROLE, _blockSpecimenProducers);
    }

    /**
     * Enables the operator instance. The operators need to call that function before they can start submitting proofs
     */
    function enableBRPOperator(address operator) external onlyOperatorManager(operator) {
        _enableOperator(operator, BLOCK_RESULT_PRODUCER_ROLE, _blockResultProducers);
    }

    /**
     * Enables the operator instance. The operators need to call that function before they can start submitting proofs
     */
    function _enableOperator(
        address operator,
        bytes32 role,
        EnumerableSetUpgradeable.AddressSet storage operators
    ) internal {
        require(operatorRoles[operator] == role, "Operator does not perform the requested role");
        require(!operators.contains(operator), "Operator is already enabled");
        uint128 validatorId = validatorIDs[operator];
        operators.add(operator);
        _validatorActiveOperatorsCounters[validatorId]++;
        // if no operator was enabled we need to enable the validator instance
        if (_validatorActiveOperatorsCounters[validatorId] == 1) _stakingInterface.enableValidator(validatorId);
        emit OperatorEnabled(operator);
    }

    /**
     * Disables the operator instance. The operator cannot submit proofs its instance got disabled.
     * If all addresses of the operator are disabled, then the operator (validator) instance will get disabled on the staking contract
     */
    function disableBSPOperator(address operator) external onlyOperatorManager(operator) {
        _disableOperator(operator, BLOCK_SPECIMEN_PRODUCER_ROLE, _blockSpecimenProducers);
    }

    /**
     * Disables the operator instance. The operator cannot submit proofs its instance got disabled.
     * If all addresses of the operator are disabled, then the operator (validator) instance will get disabled on the staking contract
     */
    function disableBRPOperator(address operator) external onlyOperatorManager(operator) {
        _disableOperator(operator, BLOCK_RESULT_PRODUCER_ROLE, _blockResultProducers);
    }

    /**
     * Disables the operator instance. The operator cannot submit proofs after its instance got disabled.
     * If all addresses of the operator are disabled, then the operator (validator) instance will get disabled on the staking contract
     */
    function _disableOperator(
        address operator,
        bytes32 role,
        EnumerableSetUpgradeable.AddressSet storage operators
    ) internal {
        require(operatorRoles[operator] == role, "Operator does not perform the requested role");
        require(operators.contains(operator), "Operator is already disabled");
        _removeOperatorFromActiveInstances(operator, operators);
        emit OperatorDisabled(operator);
    }

    /**
     * Adds the given address to the block specimen producers set
     */
    function addBSPOperator(address operator, uint128 validatorId) external onlyGovernor {
        _addOperator(operator, validatorId, BLOCK_SPECIMEN_PRODUCER_ROLE);
    }

    /**
     * Adds the given address to the block result producers set
     */
    function addBRPOperator(address operator, uint128 validatorId) external onlyGovernor {
        _addOperator(operator, validatorId, BLOCK_RESULT_PRODUCER_ROLE);
    }

    /**
     * Adds the given address to the given operator role set
     */
    function _addOperator(
        address operator,
        uint128 validatorId,
        bytes32 role
    ) internal {
        require(operatorRoles[operator] == 0, "Operator already exists");
        operatorRoles[operator] = role;
        validatorIDs[operator] = validatorId;
        _validatorOperators[validatorId].add(operator);
        emit OperatorAdded(operator, validatorId, role);
    }

    /**
     * Removes the given address from the block specimen producers set
     */
    function removeBSPOperator(address operator) external onlyGovernor {
        _removeOperator(operator, BLOCK_SPECIMEN_PRODUCER_ROLE, _blockSpecimenProducers);
    }

    /**
     * Removes the given address from the block specimen producers set
     */
    function removeBRPOperator(address operator) external onlyGovernor {
        _removeOperator(operator, BLOCK_RESULT_PRODUCER_ROLE, _blockResultProducers);
    }

    /**
     * Removes the given address from the operators set
     */
    function _removeOperator(
        address operator,
        bytes32 role,
        EnumerableSetUpgradeable.AddressSet storage operators
    ) internal {
        require(operatorRoles[operator] == role, "Operator does not perform the requested role");
        if (operators.contains(operator)) _removeOperatorFromActiveInstances(operator, operators);
        _validatorOperators[validatorIDs[operator]].remove(operator);
        validatorIDs[operator] = 0;
        operatorRoles[operator] = 0;
        emit OperatorRemoved(operator);
    }

    /**
     * Disables the operator instance.
     * If all addresses of the operator are disabled, then the operator (validator) instance will get disabled on the staking contract
     */
    function _removeOperatorFromActiveInstances(address operator, EnumerableSetUpgradeable.AddressSet storage operators) internal {
        operators.remove(operator);
        uint128 validatorId = validatorIDs[operator];
        _validatorActiveOperatorsCounters[validatorId]--;
        // if there are not more enabled operators left we need to disable the validator instance too
        if (_validatorActiveOperatorsCounters[validatorId] == 0) _stakingInterface.disableValidator(validatorId, block.number);
    }

    /**
     * Adds the given address to the auditors set
     */
    function addAuditor(address auditor) external onlyGovernor {
        require(operatorRoles[auditor] == 0, "Operator already exists");
        operatorRoles[auditor] = AUDITOR_ROLE;
        _auditors.add(auditor);
        emit OperatorAdded(auditor, 0, AUDITOR_ROLE);
    }

    /**
     * Removes the given address from the auditors set
     */
    function removeAuditor(address auditor) external onlyGovernor {
        require(operatorRoles[auditor] == AUDITOR_ROLE, "Operator is not auditor");
        operatorRoles[auditor] = 0;
        _auditors.remove(auditor);
        emit OperatorRemoved(auditor);
    }

    /**
     * Adds the given address to the governors set
     */
    function addGovernor(address governor) external onlyOwner {
        require(operatorRoles[governor] == 0, "Operator already exists");
        operatorRoles[governor] = GOVERNANCE_ROLE;
        _governors.add(governor);
        emit OperatorAdded(governor, 0, GOVERNANCE_ROLE);
    }

    /**
     * Removes the given address from the governors set
     */
    function removeGovernor(address governor) external onlyOwner {
        require(operatorRoles[governor] == GOVERNANCE_ROLE, "Operator is not governor");
        operatorRoles[governor] = 0;
        _governors.remove(governor);
        emit OperatorRemoved(governor);
    }

    /**
     * Updates the amount of tokens required to stake in order to be able to submit the proofs
     */
    function setBSPRequiredStake(uint128 newStakeAmount) public onlyGovernor {
        _bspRequiredStake = newStakeAmount;
        emit MinimumRequiredStakeChanged(newStakeAmount);
    }

    /**
     * Updates the amount of tokens required to stake in order to be able to submit the proofs
     */
    function setBRPRequiredStake(uint128 newStakeAmount) public onlyGovernor {
        _brpRequiredStake = newStakeAmount;
        emit MinimumRequiredBlockResultStakeChanged(newStakeAmount);
    }

    /**
     * Updates the address of the staking contract
     */
    function setStakingInterface(address stakingContractAddress) public onlyGovernor {
        _stakingInterface = IOperationalStaking(stakingContractAddress);
        emit StakingInterfaceChanged(stakingContractAddress);
    }

    /**
     * Update the Block Specimen Quorum Threshold.
     */
    function setQuorumThreshold(uint256 quorum) public onlyGovernor {
        _blockSpecimenQuorum = quorum;
        emit SpecimenSessionQuorumChanged(quorum);
    }

    /**
     * Update block divisor
     */
    function setNthBlock(uint64 chainId, uint64 n) public onlyGovernor {
        _chainData[chainId].nthBlock = n;
        emit NthBlockChanged(chainId, n);
    }

    /**
     * Update the reward allocation per block specimen.
     */
    function setBlockSpecimenReward(uint128 newBlockSpecimenReward) public onlyGovernor {
        _blockSpecimenRewardAllocation = newBlockSpecimenReward;
        emit BlockSpecimenRewardChanged(newBlockSpecimenReward);
    }

    /**
     * Update the reward allocation per block specimen.
     */
    function setBlockResultReward(uint128 newBlockResultReward) public onlyGovernor {
        _blockResultRewardAllocation = newBlockResultReward;
        emit BlockResultRewardChanged(newBlockResultReward);
    }

    /**
     * Update the duration of a specimen session in blocks
     */
    function setSessionDuration(uint64 newSessionDuration) public onlyGovernor {
        _blockSpecimenSessionDuration = newSessionDuration;
        emit SpecimenSessionDurationChanged(newSessionDuration);
    }

    /**
     * Update the minimum # of submissions required in order to reach quorum
     */
    function setMinSubmissionsRequired(uint64 minSubmissions) public onlyGovernor {
        _minSubmissionsRequired = minSubmissions;
        emit SpecimenSessionMinSubmissionChanged(minSubmissions);
    }

    /**
     * Update the max # of submissions per operator per block height
     */
    function setMaxSubmissionsPerBlockHeight(uint64 chainId, uint64 maxSubmissions) public onlyGovernor {
        _chainData[chainId].maxSubmissionsPerBlockHeight = maxSubmissions;
        emit MaxSubmissionsPerBlockHeightChanged(maxSubmissions);
    }

    /**
     * Update chain sync data
     */
    function setChainSyncData(
        uint64 chainId,
        uint256 blockOnTargetChain,
        uint256 blockOnCurrentChain,
        uint256 secondsPerBlock
    ) external onlyGovernor {
        ChainData storage cd = _chainData[chainId];
        require(secondsPerBlock > 0, "Seconds per block cannot be 0");
        cd.blockOnTargetChain = blockOnTargetChain;
        cd.blockOnCurrentChain = blockOnCurrentChain;
        cd.secondsPerBlock = secondsPerBlock;
        emit ChainSyncDataChanged(chainId, blockOnTargetChain, blockOnCurrentChain, secondsPerBlock);
    }

    /**
     * Update block height submission threshold for live sync
     */
    function setBlockHeightSubmissionsThreshold(uint64 chainId, uint64 threshold) external onlyGovernor {
        _chainData[chainId].allowedThreshold = threshold;
        emit BlockHeightSubmissionThresholdChanged(chainId, threshold);
    }

    /**
     * Update seconds per block on the chain where the ProofChain is deployed
     */
    function setSecondsPerBlock(uint64 secondsPerBlock) external onlyGovernor {
        _secondsPerBlock = secondsPerBlock;
        emit SecondsPerBlockChanged(secondsPerBlock);
    }

    function submitBlockSpecimenProof(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 specimenHash,
        string calldata storageURL
    ) external {
        _submitProof(chainId, blockHeight, blockHash, specimenHash, storageURL, true);
    }

    function submitBlockResultProof(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 specimenHash,
        string calldata storageURL
    ) external {
        _submitProof(chainId, blockHeight, blockHash, specimenHash, storageURL, false);
    }

    /**
     * That function exists because submitProof has too many local variables
     */
    function _startSession(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 specimenHash,
        ChainData storage cd,
        BlockSpecimenSession storage session,
        bool bspSession,
        SessionParticipantData storage participantsData
    ) internal {
        require(!session.requiresAudit, "Session submissions have closed");
        uint256 currentBlockOnTargetChain = cd.blockOnTargetChain + (((block.number - cd.blockOnCurrentChain) * _secondsPerBlock) / cd.secondsPerBlock);
        uint256 lowerBound = currentBlockOnTargetChain >= cd.allowedThreshold ? currentBlockOnTargetChain - cd.allowedThreshold : 0;
        require(lowerBound <= blockHeight && blockHeight <= currentBlockOnTargetChain + cd.allowedThreshold, "Block height is out of bounds for live sync");
        session.sessionDeadline = uint64(block.number + _blockSpecimenSessionDuration);
        (uint128 baseStake, uint128 delegateStakes) = _stakingInterface.getValidatorCompoundedStakingData(validatorIDs[msg.sender]);
        require(baseStake >= (bspSession ? _bspRequiredStake : _brpRequiredStake), "Insufficiently staked to submit");
        participantsData.stake = baseStake + delegateStakes;
        session.blockHashesRaw.push(blockHash);
        BlockHash storage bh = session.blockHashes[blockHash];
        bh.specimenHashes.push(specimenHash);
        bh.participants[specimenHash].push(msg.sender);
        participantsData.submissionCounter++;
        // no need to have a separate session started event for BRP or BSP since there is another submit proof event emitted
        emit SessionStarted(chainId, blockHeight, session.sessionDeadline);
    }

    /**
     * Block Specimen Producers submit their block specimen proofs using this function.
     */
    function _submitProof(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 specimenHash,
        string calldata storageURL,
        bool bspSession
    ) internal {
        if (bspSession) require(_blockSpecimenProducers.contains(msg.sender), "Sender is not BLOCK_SPECIMEN_PRODUCER_ROLE");
        else require(_blockResultProducers.contains(msg.sender), "Sender is not BLOCK_RESULT_PRODUCER_ROLE");

        ChainData storage cd = _chainData[chainId];
        require(cd.nthBlock != 0, "Invalid chain ID");
        require(blockHeight % cd.nthBlock == 0, "Invalid block height");

        BlockSpecimenSession storage session = bspSession ? _sessions[chainId][blockHeight] : _blockResultSessions[chainId][blockHeight];
        uint64 sessionDeadline = session.sessionDeadline;
        SessionParticipantData storage participantsData = session.participantsData[msg.sender];
        // if this is the first specimen to be submitted for a block, initialize a new session
        if (sessionDeadline == 0) {
            _startSession(chainId, blockHeight, blockHash, specimenHash, cd, session, bspSession, participantsData);
        } else {
            require(block.number <= sessionDeadline, "Session submissions have closed");
            require(participantsData.submissionCounter < cd.maxSubmissionsPerBlockHeight, "Max submissions limit exceeded");

            BlockHash storage bh = session.blockHashes[blockHash];
            bytes32[] storage specimenHashes = bh.specimenHashes;
            if (participantsData.stake != 0) {
                // check if it was submitted for the same block hash
                // this should be at most 10 iterations
                for (uint256 j = 0; j < specimenHashes.length; j++) {
                    address[] storage specimenHashParticipants = bh.participants[specimenHashes[j]];
                    for (uint256 k = 0; k < specimenHashParticipants.length; k++)
                        require(specimenHashParticipants[k] != msg.sender, "Operator already submitted for the provided block hash");
                }
            } else {
                (uint128 baseStake, uint128 delegateStakes) = _stakingInterface.getValidatorCompoundedStakingData(validatorIDs[msg.sender]);
                require(baseStake >= (bspSession ? _bspRequiredStake : _brpRequiredStake), "Insufficiently staked to submit");
                participantsData.stake = baseStake + delegateStakes;
            }

            address[] storage participants = bh.participants[specimenHash];
            if (specimenHashes.length != 0) {
                if (participants.length == 0) specimenHashes.push(specimenHash);
            } else {
                session.blockHashesRaw.push(blockHash);
                specimenHashes.push(specimenHash);
            }

            participants.push(msg.sender);
            participantsData.submissionCounter++;
        }
        _urls[specimenHash].push(storageURL);
        if (bspSession) emit BlockSpecimenProductionProofSubmitted(chainId, blockHeight, blockHash, specimenHash, storageURL, participantsData.stake);
        else emit BlockResultProductionProofSubmitted(chainId, blockHeight, blockHash, specimenHash, storageURL, participantsData.stake);
    }

    /**
     * This function is called to check whether the sesion is open for the given chain id and block height
     */
    function isSessionOpen(
        uint64 chainId,
        uint64 blockHeight,
        bool bspSession,
        address operator
    ) public view returns (bool) {
        BlockSpecimenSession storage session = bspSession ? _sessions[chainId][blockHeight] : _blockResultSessions[chainId][blockHeight];
        uint64 sessionDeadline = session.sessionDeadline;
        SessionParticipantData storage participantsData = session.participantsData[operator];
        // assuming for brp sessions it can only submit once since only one block specimen is finalized right now
        bool submissionLimitExceeded = bspSession
            ? participantsData.submissionCounter == _chainData[chainId].maxSubmissionsPerBlockHeight
            : participantsData.submissionCounter == 1;
        return (!submissionLimitExceeded && block.number <= sessionDeadline) || sessionDeadline == 0;
    }

    /**
     * This function is called when a quorum of equivalent hashes have been submitted for a Block Specimen Session.
     */
    function finalizeAndRewardSpecimenSession(uint64 chainId, uint64 blockHeight) public {
        _finalizeAndRewardSession(chainId, blockHeight, true);
    }

    /**
     * This function is called when a quorum of equivalent hashes have been submitted for a Block Specimen Session.
     */
    function finalizeAndRewardBlockResultSession(uint64 chainId, uint64 blockHeight) public {
        _finalizeAndRewardSession(chainId, blockHeight, false);
    }

    /**
     * This function is called when a quorum of equivalent hashes have been submitted for a Block Specimen Session.
     */
    function _finalizeAndRewardSession(
        uint64 chainId,
        uint64 blockHeight,
        bool bspSession
    ) internal {
        BlockSpecimenSession storage session = bspSession ? _sessions[chainId][blockHeight] : _blockResultSessions[chainId][blockHeight];
        uint64 sessionDeadline = session.sessionDeadline;
        require(block.number > sessionDeadline, "Session not past deadline");
        require(!session.requiresAudit, "Session cannot be finalized");
        require(sessionDeadline != 0, "Session not started");

        uint256 contributorsN;
        bytes32 specimenHash;

        uint256 max;
        bytes32 agreedBlockHash;
        bytes32 agreedSpecimenHash;

        bytes32[] storage blockHashesRaw = session.blockHashesRaw;
        bytes32 rawBlockHash;

        // find the block hash and specimen hashes that the quorum agrees on by finding the specimen hash with the highest number of participants
        for (uint256 i = 0; i < blockHashesRaw.length; i++) {
            rawBlockHash = blockHashesRaw[i];
            BlockHash storage bh = session.blockHashes[rawBlockHash];
            for (uint256 j = 0; j < bh.specimenHashes.length; j++) {
                specimenHash = bh.specimenHashes[j];
                uint256 len = bh.participants[specimenHash].length;
                contributorsN += len;
                if (len > max) {
                    max = len;
                    agreedBlockHash = rawBlockHash;
                    agreedSpecimenHash = specimenHash;
                }
            }
        }
        // check if the number of submissions is sufficient and if the quorum is achieved
        if (_minSubmissionsRequired <= max && (max * _DIVIDER) / contributorsN > _blockSpecimenQuorum)
            _rewardParticipants(session, chainId, blockHeight, agreedBlockHash, agreedSpecimenHash, bspSession);
        else {
            if (bspSession) emit BSPQuorumNotReached(chainId, blockHeight);
            else emit BRPQuorumNotReached(chainId, blockHeight);
        }

        session.requiresAudit = true;
        // set session deadline to 0 to release gas
        session.sessionDeadline = 0;
    }

    /**
     * Called by Auditor role when a quorum is not reached. The auditor's submitted hash is
     * the definitive truth.
     */
    function arbitrateBlockSpecimenSession(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 definitiveSpecimenHash
    ) public {
        _arbitrateSession(chainId, blockHeight, blockHash, definitiveSpecimenHash, true);
    }

    /**
     * Called by Auditor role when a quorum is not reached. The auditor's submitted hash is
     * the definitive truth.
     */
    function arbitrateBlockResultSession(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 definitiveSpecimenHash
    ) public {
        _arbitrateSession(chainId, blockHeight, blockHash, definitiveSpecimenHash, false);
    }

    /**
     * Called by Auditor role when a quorum is not reached. The auditor's submitted hash is
     * the definitive truth.
     */
    function _arbitrateSession(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 definitiveSpecimenHash,
        bool bspSession
    ) internal {
        require(_auditors.contains(msg.sender), "Sender is not AUDITOR_ROLE");
        BlockSpecimenSession storage session = bspSession ? _sessions[chainId][blockHeight] : _blockResultSessions[chainId][blockHeight];
        require(session.requiresAudit, "Session must be finalized before audit");
        _rewardParticipants(session, chainId, blockHeight, blockHash, definitiveSpecimenHash, bspSession);
    }

    function _rewardParticipants(
        BlockSpecimenSession storage session,
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 specimenHash,
        bool bspSession
    ) internal {
        address participant;
        address[] storage participants = session.blockHashes[blockHash].participants[specimenHash];
        uint256 len = participants.length;
        uint128[] memory ids = new uint128[](len);
        uint128[] memory rewards = new uint128[](len);
        uint128 totalStake;
        mapping(address => SessionParticipantData) storage participantsData = session.participantsData;
        for (uint256 i = 0; i < len; i++) {
            totalStake += participantsData[participants[i]].stake;
        }
        for (uint256 i = 0; i < len; i++) {
            participant = participants[i];
            SessionParticipantData storage pd = participantsData[participant];
            ids[i] = validatorIDs[participant];
            rewards[i] = uint128((uint256(pd.stake) * uint256(_blockSpecimenRewardAllocation)) / totalStake);
            // release gas if possible
            if (pd.submissionCounter == 1) {
                pd.submissionCounter = 0;
                pd.stake = 0;
            }
        }
        _stakingInterface.rewardValidators(ids, rewards);
        if (bspSession) emit BlockSpecimenRewardAwarded(chainId, blockHeight, blockHash, specimenHash);
        else emit BlockResultRewardAwarded(chainId, blockHeight, blockHash, specimenHash);

        delete session.blockHashes[blockHash]; // release gas
    }

    /**
     * Returns contract meta data
     */
    function getMetadata()
        public
        view
        returns (
            address stakingInterface,
            uint128 blockSpecimenRewardAllocation,
            uint128 blockResultRewardAllocation,
            uint64 blockSpecimenSessionDuration,
            uint64 minSubmissionsRequired,
            uint256 blockSpecimenQuorum,
            uint256 secondsPerBlock
        )
    {
        return (
            address(_stakingInterface),
            _blockSpecimenRewardAllocation,
            _blockResultRewardAllocation,
            _blockSpecimenSessionDuration,
            _minSubmissionsRequired,
            _blockSpecimenQuorum,
            _secondsPerBlock
        );
    }

    /**
     * Returns data used for chain sync
     */
    function getChainData(uint64 chainId)
        external
        view
        returns (
            uint256 blockOnTargetChain,
            uint256 blockOnCurrentChain,
            uint256 secondsPerBlock,
            uint128 allowedThreshold,
            uint128 maxSubmissionsPerBlockHeight,
            uint64 nthBlock
        )
    {
        ChainData memory cd = _chainData[chainId];
        return (cd.blockOnTargetChain, cd.blockOnCurrentChain, cd.secondsPerBlock, cd.allowedThreshold, cd.maxSubmissionsPerBlockHeight, cd.nthBlock);
    }

    /**
     * Returns all operator addresses (disabled and enabled) of a given validator
     */
    function getOperators(uint128 validatorId) external view returns (address[] memory) {
        return _validatorOperators[validatorId].values();
    }

    /**
     * Returns all enabled operators by role type
     */
    function getAllOperators()
        external
        view
        returns (
            address[] memory _bsps,
            address[] memory __governors,
            address[] memory __auditors,
            address[] memory _brps
        )
    {
        return (_blockSpecimenProducers.values(), _governors.values(), _auditors.values(), _blockResultProducers.values());
    }

    /**
     * Returns required stake and enabled block specimen producer operators
     */
    function getBSPRoleData() external view returns (uint128 requiredStake, address[] memory activeMembers) {
        return (_bspRequiredStake, _blockSpecimenProducers.values());
    }

    /**
     * Returns required stake and enabled block result producer operators
     */
    function getBRPRoleData() external view returns (uint128 requiredStake, address[] memory activeMembers) {
        return (_brpRequiredStake, _blockResultProducers.values());
    }

    function getURLS(bytes32 specimenhash) external view returns (string[] memory) {
        return _urls[specimenhash];
    }

    /**
     * Returns true if the given operator is enabled.
     * Returns false if the operator is disabled or does not exist
     */
    function isEnabled(address operator) external view returns (bool) {
        return _blockSpecimenProducers.contains(operator) || _blockResultProducers.contains(operator);
    }
}

File 2 of 7 : IOperationalStaking.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

interface IOperationalStaking {
    function getValidatorMetadata(uint128 validatorId)
        external
        view
        returns (
            address _address,
            uint128 staked,
            uint128 delegated,
            uint128 commissionRate
        );

    function getValidatorStakingData(uint128 validatorId) external view returns (uint128 staked, uint128 delegated);

    function getValidatorCompoundedStakingData(uint128 validatorId) external view returns (uint128 staked, uint128 delegated);

    function rewardValidators(uint128[] calldata validatorId, uint128[] calldata amount) external;

    function addValidator(address validator, uint128 commissionRate) external returns (uint256 id);

    function disableValidator(uint128 validatorId, uint256 blockNumber) external;

    function enableValidator(uint128 validatorId) external;
}

File 3 of 7 : EnumerableSetUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 *  Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
 *  See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 *  In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.
 * ====
 */
library EnumerableSetUpgradeable {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        return _values(set._inner);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 4 of 7 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 5 of 7 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 6 of 7 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
     * initialization step. This is essential to configure modules that are added through upgrades and that require
     * initialization.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }
}

File 7 of 7 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"blockHeight","type":"uint64"}],"name":"BRPQuorumNotReached","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"blockHeight","type":"uint64"}],"name":"BSPQuorumNotReached","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"threshold","type":"uint64"}],"name":"BlockHeightSubmissionThresholdChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"resultHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"storageURL","type":"string"},{"indexed":false,"internalType":"uint128","name":"submittedStake","type":"uint128"}],"name":"BlockResultProductionProofSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"blockResultHash","type":"bytes32"}],"name":"BlockResultRewardAwarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newBlockSpecimenRewardAllocation","type":"uint128"}],"name":"BlockResultRewardChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newQuorumThreshold","type":"uint256"}],"name":"BlockResultSessionQuorumChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"storageURL","type":"string"},{"indexed":false,"internalType":"uint128","name":"submittedStake","type":"uint128"}],"name":"BlockSpecimenProductionProofSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newBlockResultRewardAllocation","type":"uint128"}],"name":"BlockSpecimenResultChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"blockhash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"specimenhash","type":"bytes32"}],"name":"BlockSpecimenRewardAwarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newBlockSpecimenRewardAllocation","type":"uint128"}],"name":"BlockSpecimenRewardChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"blockOnTargetChain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockOnCurrentChain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"secondsPerBlock","type":"uint256"}],"name":"ChainSyncDataChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxSubmissions","type":"uint256"}],"name":"MaxSubmissionsPerBlockHeightChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newStakeRequirement","type":"uint128"}],"name":"MinimumRequiredBlockResultStakeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newStakeRequirement","type":"uint128"}],"name":"MinimumRequiredStakeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"nthBlock","type":"uint64"}],"name":"NthBlockChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"OperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"secondsPerBlock","type":"uint64"}],"name":"SecondsPerBlockChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"SessionStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newSessionDuration","type":"uint64"}],"name":"SpecimenSessionDurationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"minSubmissions","type":"uint64"}],"name":"SpecimenSessionMinSubmissionChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newQuorumThreshold","type":"uint256"}],"name":"SpecimenSessionQuorumChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newInterfaceAddress","type":"address"}],"name":"StakingInterfaceChanged","type":"event"},{"inputs":[],"name":"AUDITOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BLOCK_RESULT_PRODUCER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BLOCK_SPECIMEN_PRODUCER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNANCE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"}],"name":"addAuditor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"addBRPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"addBSPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"governor","type":"address"}],"name":"addGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"uint128","name":"commissionRate","type":"uint128"}],"name":"addValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"definitiveSpecimenHash","type":"bytes32"}],"name":"arbitrateBlockResultSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"definitiveSpecimenHash","type":"bytes32"}],"name":"arbitrateBlockSpecimenSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"disableBRPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"disableBSPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"disableValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"enableBRPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"enableBSPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"}],"name":"finalizeAndRewardBlockResultSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"}],"name":"finalizeAndRewardSpecimenSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllOperators","outputs":[{"internalType":"address[]","name":"_bsps","type":"address[]"},{"internalType":"address[]","name":"__governors","type":"address[]"},{"internalType":"address[]","name":"__auditors","type":"address[]"},{"internalType":"address[]","name":"_brps","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBRPRoleData","outputs":[{"internalType":"uint128","name":"requiredStake","type":"uint128"},{"internalType":"address[]","name":"activeMembers","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBSPRoleData","outputs":[{"internalType":"uint128","name":"requiredStake","type":"uint128"},{"internalType":"address[]","name":"activeMembers","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"}],"name":"getChainData","outputs":[{"internalType":"uint256","name":"blockOnTargetChain","type":"uint256"},{"internalType":"uint256","name":"blockOnCurrentChain","type":"uint256"},{"internalType":"uint256","name":"secondsPerBlock","type":"uint256"},{"internalType":"uint128","name":"allowedThreshold","type":"uint128"},{"internalType":"uint128","name":"maxSubmissionsPerBlockHeight","type":"uint128"},{"internalType":"uint64","name":"nthBlock","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMetadata","outputs":[{"internalType":"address","name":"stakingInterface","type":"address"},{"internalType":"uint128","name":"blockSpecimenRewardAllocation","type":"uint128"},{"internalType":"uint128","name":"blockResultRewardAllocation","type":"uint128"},{"internalType":"uint64","name":"blockSpecimenSessionDuration","type":"uint64"},{"internalType":"uint64","name":"minSubmissionsRequired","type":"uint64"},{"internalType":"uint256","name":"blockSpecimenQuorum","type":"uint256"},{"internalType":"uint256","name":"secondsPerBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"getOperators","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"specimenhash","type":"bytes32"}],"name":"getURLS","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"stakingContract","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"isEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bool","name":"bspSession","type":"bool"},{"internalType":"address","name":"operator","type":"address"}],"name":"isSessionOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operatorRoles","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"}],"name":"removeAuditor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"removeBRPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"removeBSPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"governor","type":"address"}],"name":"removeGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newStakeAmount","type":"uint128"}],"name":"setBRPRequiredStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newStakeAmount","type":"uint128"}],"name":"setBSPRequiredStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"threshold","type":"uint64"}],"name":"setBlockHeightSubmissionsThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newBlockResultReward","type":"uint128"}],"name":"setBlockResultReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newBlockSpecimenReward","type":"uint128"}],"name":"setBlockSpecimenReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint256","name":"blockOnTargetChain","type":"uint256"},{"internalType":"uint256","name":"blockOnCurrentChain","type":"uint256"},{"internalType":"uint256","name":"secondsPerBlock","type":"uint256"}],"name":"setChainSyncData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"maxSubmissions","type":"uint64"}],"name":"setMaxSubmissionsPerBlockHeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"minSubmissions","type":"uint64"}],"name":"setMinSubmissionsRequired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"n","type":"uint64"}],"name":"setNthBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"quorum","type":"uint256"}],"name":"setQuorumThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"secondsPerBlock","type":"uint64"}],"name":"setSecondsPerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newSessionDuration","type":"uint64"}],"name":"setSessionDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stakingContractAddress","type":"address"}],"name":"setStakingInterface","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"internalType":"string","name":"storageURL","type":"string"}],"name":"submitBlockResultProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"internalType":"string","name":"storageURL","type":"string"}],"name":"submitBlockSpecimenProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"validatorIDs","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50615c2b80620000216000396000f3fe608060405234801561001057600080fd5b506004361061034c5760003560e01c806389587f05116101bd578063cc96e413116100f9578063df4112c2116100a2578063e6116cfd1161007c578063e6116cfd14610917578063eecdac881461092a578063f2fde38b1461093d578063f36c8f5c1461095057600080fd5b8063df4112c2146108de578063e3201409146108f1578063e429cef11461090457600080fd5b8063d5839da9116100d3578063d5839da914610893578063d911c632146108b3578063dd36a8d5146108cb57600080fd5b8063cc96e4131461084d578063cf64a01d14610860578063d3a8b2a81461087357600080fd5b80639914628411610166578063ad9e91ee11610140578063ad9e91ee14610801578063c0e745d214610814578063c384678914610827578063c4499cb91461083a57600080fd5b806399146284146107b45780639c49d8ee146107c7578063a2e7e441146107ee57600080fd5b80639015d371116101975780639015d37114610776578063920036b71461079957806393742b56146107a157600080fd5b806389587f05146107285780638da5cb5b1461073b5780638ecd30bc1461076357600080fd5b8063485cc9551161028c57806367585e44116102355780636e1d616e1161020f5780636e1d616e14610648578063715018a61461066f57806372ab8568146106775780637a5b4f591461068a57600080fd5b806367585e44146106025780636ab9d8e8146106155780636b7511cb1461063557600080fd5b80635a5e84f2116102665780635a5e84f2146105c95780635ebdedfa146105dc5780636543413a146105ef57600080fd5b8063485cc955146104b45780635137b8b9146104c757806354cfa69f146104da57600080fd5b80632f01798e116102f957806341c1278d116102d357806341c1278d1461044657806341ca4a551461047b5780634414beeb1461048e5780634524c7e1146104a157600080fd5b80632f01798e1461040d5780633646aded146104205780633c4a25d01461043357600080fd5b80631fd55ae91161032a5780631fd55ae9146103d1578063222388c2146103e75780632c58ed42146103fa57600080fd5b80630d92f4ed1461035157806313e3f452146103a9578063151fd8f3146103be575b600080fd5b61038361035f3660046152d9565b6072602052600090815260409020546fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6103bc6103b73660046152d9565b610977565b005b6103bc6103cc366004615313565b610aed565b6103d9610b05565b6040516103a092919061540a565b6103bc6103f536600461545b565b610b46565b6103bc610408366004615494565b610beb565b6103bc61041b3660046154c7565b610ce4565b6103bc61042e3660046152d9565b610dc8565b6103bc6104413660046152d9565b610eb1565b61046d7f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f81565b6040519081526020016103a0565b6103bc6104893660046152d9565b611010565b6103bc61049c3660046154e2565b61117c565b6103bc6104af366004615524565b611190565b6103bc6104c236600461553d565b61123a565b6103bc6104d536600461556b565b611575565b61057d6104e83660046154c7565b67ffffffffffffffff908116600090815260776020908152604091829020825160c08101845281548082526001830154938201849052600283015494820185905260038301546fffffffffffffffffffffffffffffffff80821660608501819052700100000000000000000000000000000000909204166080840181905260049094015490961660a090920182905295929492565b604080519687526020870195909552938501929092526fffffffffffffffffffffffffffffffff908116606085015216608083015267ffffffffffffffff1660a082015260c0016103a0565b6103bc6105d736600461556b565b61164f565b6103bc6105ea366004615494565b611729565b6103bc6105fd366004615313565b611735565b6103bc610610366004615494565b611745565b61046d6106233660046152d9565b60746020526000908152604090205481565b6103bc6106433660046152d9565b611841565b61046d7f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f581565b6103bc6118e6565b6103bc6106853660046152d9565b6118fa565b606554606854607b546069546066546067546040805173ffffffffffffffffffffffffffffffffffffffff90971687526fffffffffffffffffffffffffffffffff95861660208801527001000000000000000000000000000000009094049094169285019290925267ffffffffffffffff80821660608601526801000000000000000090910416608084015260a083015260c082015260e0016103a0565b6103bc61073636600461556b565b611a66565b60335460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103a0565b6103bc610771366004615494565b611b4b565b6107896107843660046152d9565b611b57565b60405190151581526020016103a0565b6103d9611bb4565b6103bc6107af3660046154c7565b611bd9565b6103bc6107c2366004615588565b611cc4565b61046d7f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c81565b6103bc6107fc36600461545b565b611e1f565b6103bc61080f3660046155c1565b611f43565b6103bc61082236600461556b565b612051565b6103bc6108353660046154e2565b612136565b6107896108483660046155ed565b612144565b6103bc61085b36600461545b565b61229a565b6103bc61086e3660046152d9565b61233b565b61088661088136600461556b565b6123dd565b6040516103a0919061564a565b6108a66108a1366004615524565b61240a565b6040516103a0919061565d565b6108bb6124f6565b6040516103a09493929190615734565b6103bc6108d93660046154c7565b612532565b6103bc6108ec3660046152d9565b6125e4565b6103bc6108ff366004615494565b612750565b6103bc6109123660046152d9565b612839565b6103bc6109253660046152d9565b612a06565b6103bc6109383660046152d9565b612ba2565b6103bc61094b3660046152d9565b612c89565b61046d7f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb181565b60655473ffffffffffffffffffffffffffffffffffffffff8281166000908152607260205260408082205490517f87326a0c0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015284939192909116906387326a0c90602401608060405180830381865afa158015610a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a32919061578c565b50919250505073ffffffffffffffffffffffffffffffffffffffff81163314610abc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f53656e646572206973206e6f74206f70657261746f72206d616e61676572000060448201526064015b60405180910390fd5b610ae8837f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c606c612d3d565b505050565b610afd8686868686866001612ecf565b505050505050565b60685460009060609070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16610b3e606c613830565b915091509091565b336000908152606f6020526040902054610bbc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b610be782827f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f613844565b5050565b336000908152606f6020526040902054610c61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff82811660008181526077602090815260409182902060030180547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169486169485179055905192835290917f4e4c0afc3a2b327c2f061f8ff5190a491f1042ba8f292a887bab97840947b7a9910160405180910390a25050565b336000908152606f6020526040902054610d5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83169081179091556040519081527f94bc488f4d9a985dd5f9d11e8f0a614a62828888eb65b704a90fa852be937549906020015b60405180910390a150565b336000908152606f6020526040902054610e3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f70016f37fc9a299f674d1e3083a27743406649810887ed947a79884b064d2de990602001610dbd565b610eb96139b9565b73ffffffffffffffffffffffffffffffffffffffff811660009081526074602052604090205415610f46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f70657261746f7220616c7265616479206578697374730000000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff811660009081526074602052604090207f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19055610f99606e82613a3a565b506040805173ffffffffffffffffffffffffffffffffffffffff83168152600060208201527f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb1918101919091527f797ca55fc7be0f65c71f10996f7a16f801094f8ae3811874afc5a39730772a4290606001610dbd565b60655473ffffffffffffffffffffffffffffffffffffffff8281166000908152607260205260408082205490517f87326a0c0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015284939192909116906387326a0c90602401608060405180830381865afa1580156110a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cb919061578c565b50919250505073ffffffffffffffffffffffffffffffffffffffff81163314611150576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f53656e646572206973206e6f74206f70657261746f72206d616e6167657200006044820152606401610ab3565b610ae8837f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f6078613a5c565b61118a848484846001613d3e565b50505050565b336000908152606f6020526040902054611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b60668190556040518181527eec8eefea39d742ff523b872c1931ff4d509ab873041c5d6e237d5f0fc053f890602001610dbd565b600054610100900460ff161580801561125a5750600054600160ff909116105b806112745750303b158015611274575060005460ff166001145b611300576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ab3565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561135e57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b611366613ebe565b611371606e33613a3a565b5061139d606a7f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb1613f5d565b506113c9606a7f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c613f5d565b506113f5606a7f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f5613f5d565b5061140c6104af6002670de0b6b3a764000061583e565b61141b655af3107a4000611a66565b61142560f0610ce4565b61142f6002611bd9565b61143882610dc8565b611443606e33613f69565b5073ffffffffffffffffffffffffffffffffffffffff831660009081526074602052604090207f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19055611497606e84613a3a565b506040805173ffffffffffffffffffffffffffffffffffffffff85168152600060208201527f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb18183015290517f797ca55fc7be0f65c71f10996f7a16f801094f8ae3811874afc5a39730772a429181900360600190a18015610ae857600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a1505050565b336000908152606f60205260409020546115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606880546fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000918416918202179091556040519081527fb6c040bb0324b47cbf9a620cce03b311e24597626a57322173d5d5465f739d2790602001610dbd565b336000908152606f60205260409020546116c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b607b80546fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000918416918202179091556040519081527fa425d7d9b858a4250625446e4504257053202ae93ba0d1dea68dce7ec87a05c590602001610dbd565b610be782826000613f8b565b610afd8686868686866000612ecf565b336000908152606f60205260409020546117bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff82811660009081526077602090815260409182902060030180546fffffffffffffffffffffffffffffffff16938516700100000000000000000000000000000000810294909417905590519182527f1bca1fb481202bb14258ce1030d54e9e7bafc8b696d96b9eb733826e58a3a030910160405180910390a15050565b336000908152606f60205260409020546118b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b6118e3817f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f6078614348565b50565b6118ee6139b9565b6118f86000614508565b565b60655473ffffffffffffffffffffffffffffffffffffffff8281166000908152607260205260408082205490517f87326a0c0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015284939192909116906387326a0c90602401608060405180830381865afa158015611991573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b5919061578c565b50919250505073ffffffffffffffffffffffffffffffffffffffff81163314611a3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f53656e646572206973206e6f74206f70657261746f72206d616e6167657200006044820152606401610ab3565b610ae8837f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f6078612d3d565b336000908152606f6020526040902054611adc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606880547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff83169081179091556040519081527f01eb821dd596243f2f8c5f6c7478e281b855ac12a9f4be2c486cb2778a0bb81e90602001610dbd565b610be782826001613f8b565b73ffffffffffffffffffffffffffffffffffffffff81166000908152606d6020526040812054151580611bae575073ffffffffffffffffffffffffffffffffffffffff821660009081526079602052604090205415155b92915050565b607b546000906060906fffffffffffffffffffffffffffffffff16610b3e6078613830565b336000908152606f6020526040902054611c4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606980547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff8416908102919091179091556040519081527f28312bbddd51eea4439db773218c441a4057f6ed285c642a569f1dcdba1cc04790602001610dbd565b336000908152606f6020526040902054611d3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff8416600090815260776020526040902081611dba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f5365636f6e64732070657220626c6f636b2063616e6e6f7420626520300000006044820152606401610ab3565b8381556001810183905560028101829055604080518581526020810185905290810183905267ffffffffffffffff8616907ffd97af399d19e6be9256c99c8e52b1809cdbc4dc96816739612b6fd4e6d940b09060600160405180910390a25050505050565b336000908152606f6020526040902054611e95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b6065546040517fa2e7e44100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526fffffffffffffffffffffffffffffffff841660248301529091169063a2e7e441906044016020604051808303816000875af1158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae89190615852565b336000908152606f6020526040902054611fb9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b6065546040517fad9e91ee0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff841660048201526024810183905273ffffffffffffffffffffffffffffffffffffffff9091169063ad9e91ee90604401600060405180830381600087803b15801561203d57600080fd5b505af1158015610afd573d6000803e3d6000fd5b336000908152606f60205260409020546120c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b607b80547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff83169081179091556040519081527f3c123a1bb22d50819d69fdf807dc3a338b33bb1089acd51636778324836af17d90602001610dbd565b61118a848484846000613d3e565b600080836121775767ffffffffffffffff8087166000908152607a6020908152604080832093891683529290522061219e565b67ffffffffffffffff80871660009081526076602090815260408083209389168352929052205b600381015473ffffffffffffffffffffffffffffffffffffffff85166000908152600283016020526040812092935067ffffffffffffffff90911691908661221057815470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16600114612260565b67ffffffffffffffff89166000908152607760205260409020600301548254700100000000000000000000000000000000918290046fffffffffffffffffffffffffffffffff9081169290910416145b90508015801561227a57508267ffffffffffffffff164311155b8061228d575067ffffffffffffffff8316155b9998505050505050505050565b336000908152606f6020526040902054612310576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b610be782827f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c613844565b336000908152606f60205260409020546123b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b6118e3817f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c606c614348565b6fffffffffffffffffffffffffffffffff81166000908152607360205260409020606090611bae90613830565b6060607c6000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156124eb57838290600052602060002001805461245e9061586b565b80601f016020809104026020016040519081016040528092919081815260200182805461248a9061586b565b80156124d75780601f106124ac576101008083540402835291602001916124d7565b820191906000526020600020905b8154815290600101906020018083116124ba57829003601f168201915b50505050508152602001906001019061243f565b505050509050919050565b606080606080612506606c613830565b612510606e613830565b61251a6070613830565b6125246078613830565b935093509350935090919293565b336000908152606f60205260409020546125a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff811660678190556040517fcaf46ba335d93b98398af7142ea3e362a6b8e91c57da6bf1e8a704f86374dde090600090a250565b60655473ffffffffffffffffffffffffffffffffffffffff8281166000908152607260205260408082205490517f87326a0c0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015284939192909116906387326a0c90602401608060405180830381865afa15801561267b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269f919061578c565b50919250505073ffffffffffffffffffffffffffffffffffffffff81163314612724576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f53656e646572206973206e6f74206f70657261746f72206d616e6167657200006044820152606401610ab3565b610ae8837f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c606c613a5c565b336000908152606f60205260409020546127c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff82811660008181526077602052604080822060040180547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000169486169485179055517fbbfa9310306e8a8485d109f8be6b0a808473ce55d2e94b8ca3447c9ddb2854b49190a35050565b336000908152606f60205260409020546128af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff81166000908152607460205260409020541561293c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f70657261746f7220616c7265616479206578697374730000000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff811660009081526074602052604090207f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f5905561298f607082613a3a565b506040805173ffffffffffffffffffffffffffffffffffffffff83168152600060208201527f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f5918101919091527f797ca55fc7be0f65c71f10996f7a16f801094f8ae3811874afc5a39730772a4290606001610dbd565b336000908152606f6020526040902054612a7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff81166000908152607460205260409020547f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f514612b2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f70657261746f72206973206e6f742061756469746f720000000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260746020526040812055612b5b607082613f69565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f80c0b871b97b595b16a7741c1b06fed0c6f6f558639f18ccbce50724325dc40d90602001610dbd565b612baa6139b9565b73ffffffffffffffffffffffffffffffffffffffff81166000908152607460205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb114612c58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f70657261746f72206973206e6f7420676f7665726e6f7200000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260746020526040812055612b5b606e82613f69565b612c916139b9565b73ffffffffffffffffffffffffffffffffffffffff8116612d34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ab3565b6118e381614508565b73ffffffffffffffffffffffffffffffffffffffff83166000908152607460205260409020548214612df1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4f70657261746f7220646f6573206e6f7420706572666f726d2074686520726560448201527f7175657374656420726f6c6500000000000000000000000000000000000000006064820152608401610ab3565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600182016020526040902054612e7f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4f70657261746f7220697320616c72656164792064697361626c6564000000006044820152606401610ab3565b612e89838261457f565b60405173ffffffffffffffffffffffffffffffffffffffff841681527f23cd406c7cafe6d88c3f1c1cc16e438745a4236aec25906be2046ca16c36bd1e90602001611568565b8015612f7657336000908152606d6020526040902054612f71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f53656e646572206973206e6f7420424c4f434b5f53504543494d454e5f50524f60448201527f44554345525f524f4c45000000000000000000000000000000000000000000006064820152608401610ab3565b613012565b33600090815260796020526040902054613012576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f53656e646572206973206e6f7420424c4f434b5f524553554c545f50524f445560448201527f4345525f524f4c450000000000000000000000000000000000000000000000006064820152608401610ab3565b67ffffffffffffffff80881660009081526077602052604081206004810154909216900361309c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f496e76616c696420636861696e204944000000000000000000000000000000006044820152606401610ab3565b60048101546130b59067ffffffffffffffff16886158be565b67ffffffffffffffff1615613126576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f496e76616c696420626c6f636b206865696768740000000000000000000000006044820152606401610ab3565b6000826131585767ffffffffffffffff808a166000908152607a60209081526040808320938c1683529290522061317f565b67ffffffffffffffff808a166000908152607660209081526040808320938c168352929052205b6003810154336000908152600283016020526040812092935067ffffffffffffffff90911691908290036131c2576131bd8b8b8b8b88888b886146ca565b61373b565b8167ffffffffffffffff16431115613236576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53657373696f6e207375626d697373696f6e73206861766520636c6f736564006044820152606401610ab3565b600384015481546fffffffffffffffffffffffffffffffff7001000000000000000000000000000000009283900481169290910416106132d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d6178207375626d697373696f6e73206c696d697420657863656564656400006044820152606401610ab3565b6000898152602084905260409020815460018201906fffffffffffffffffffffffffffffffff16156134505760005b815481101561344a576000836000016000848481548110613324576133246158e5565b90600052602060002001548152602001908152602001600020905060005b8154811015613435573373ffffffffffffffffffffffffffffffffffffffff16828281548110613374576133746158e5565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1603613423576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f4f70657261746f7220616c7265616479207375626d697474656420666f72207460448201527f68652070726f766964656420626c6f636b2068617368000000000000000000006064820152608401610ab3565b8061342d81615914565b915050613342565b5050808061344290615914565b915050613301565b5061362b565b606554336000908152607260205260408082205490517f4c4a17090000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201529091829173ffffffffffffffffffffffffffffffffffffffff90911690634c4a1709906024016040805180830381865afa1580156134e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613508919061594c565b915091508861352b57607b546fffffffffffffffffffffffffffffffff16613555565b60685470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff165b6fffffffffffffffffffffffffffffffff16826fffffffffffffffffffffffffffffffff1610156135e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f496e73756666696369656e746c79207374616b656420746f207375626d6974006044820152606401610ab3565b6135ec818361597b565b85547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff9190911617855550505b60008a815260208390526040902081541561366457805460000361365f578154600181018355600083815260209020018b90555b613691565b600180870180548083018255600091825260208083209091018f9055845492830185558482529020018b90555b80546001810182556000828152602090200180547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317905583546fffffffffffffffffffffffffffffffff70010000000000000000000000000000000090910416846010613700836159af565b91906101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550505050505b6000888152607c60209081526040822080546001810182559083529120613764910188886151e6565b5084156137c95780546040517f57b0cb34d2ff9ed661f8b3c684aaee6cbf0bda5da02f4044205556817fa8e76c916137bc918e918e918e918e918e918e916fffffffffffffffffffffffffffffffff909116906159de565b60405180910390a1613823565b80546040517f8741f5bf89731b15f24deb1e84e2bbd381947f009ee378a2daa15ed8abfb94859161381a918e918e918e918e918e918e916fffffffffffffffffffffffffffffffff909116906159de565b60405180910390a15b5050505050505050505050565b6060600061383d83614bed565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260746020526040902054156138d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f70657261746f7220616c7265616479206578697374730000000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff831660009081526074602090815260408083208490556072825280832080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff87169081179091558352607390915290206139539084613a3a565b506040805173ffffffffffffffffffffffffffffffffffffffff851681526fffffffffffffffffffffffffffffffff841660208201529081018290527f797ca55fc7be0f65c71f10996f7a16f801094f8ae3811874afc5a39730772a4290606001611568565b60335473ffffffffffffffffffffffffffffffffffffffff1633146118f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ab3565b600061383d8373ffffffffffffffffffffffffffffffffffffffff8416614c49565b73ffffffffffffffffffffffffffffffffffffffff83166000908152607460205260409020548214613b10576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4f70657261746f7220646f6573206e6f7420706572666f726d2074686520726560448201527f7175657374656420726f6c6500000000000000000000000000000000000000006064820152608401610ab3565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260018201602052604090205415613b9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f70657261746f7220697320616c726561647920656e61626c656400000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff83166000908152607260205260409020546fffffffffffffffffffffffffffffffff16613be18285613a3a565b506fffffffffffffffffffffffffffffffff808216600090815260756020526040812080549092169190613c14836159af565b82546101009290920a6fffffffffffffffffffffffffffffffff818102199093169183160217909155828116600090815260756020526040902054166001039050613cef576065546040517fedff4b610000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8316600482015273ffffffffffffffffffffffffffffffffffffffff9091169063edff4b6190602401600060405180830381600087803b158015613cd657600080fd5b505af1158015613cea573d6000803e3d6000fd5b505050505b60405173ffffffffffffffffffffffffffffffffffffffff851681527f9e532d260bd7dde07708a6b1f7c64042546243d79bac23514cd74fcfc1a01fe49060200160405180910390a150505050565b33600090815260716020526040902054613db4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f53656e646572206973206e6f742041554449544f525f524f4c450000000000006044820152606401610ab3565b600081613de65767ffffffffffffffff8087166000908152607a60209081526040808320938916835292905220613e0d565b67ffffffffffffffff80871660009081526076602090815260408083209389168352929052205b600381015490915068010000000000000000900460ff16613eb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53657373696f6e206d7573742062652066696e616c697a6564206265666f726560448201527f20617564697400000000000000000000000000000000000000000000000000006064820152608401610ab3565b610afd818787878787614c98565b600054610100900460ff16613f55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ab3565b6118f8615053565b600061383d8383614c49565b600061383d8373ffffffffffffffffffffffffffffffffffffffff84166150f3565b600081613fbd5767ffffffffffffffff8085166000908152607a60209081526040808320938716835292905220613fe4565b67ffffffffffffffff80851660009081526076602090815260408083209387168352929052205b600381015490915067ffffffffffffffff1643811061405f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f53657373696f6e206e6f74207061737420646561646c696e65000000000000006044820152606401610ab3565b600382015468010000000000000000900460ff16156140da576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53657373696f6e2063616e6e6f742062652066696e616c697a656400000000006044820152606401610ab3565b8067ffffffffffffffff1660000361414e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f53657373696f6e206e6f742073746172746564000000000000000000000000006044820152606401610ab3565b6000808080806001870181805b825481101561421957828181548110614176576141766158e5565b6000918252602080832090910154808352908c905260408220909350905b6001820154811015614204578160010181815481106141b5576141b56158e5565b6000918252602080832090910154808352908490526040909120549099506141dd818c615a71565b9a50888111156141f1578098508497508996505b50806141fc81615914565b915050614194565b5050808061421190615914565b91505061415b565b5060695468010000000000000000900467ffffffffffffffff16851080159061425f575060665487614253670de0b6b3a764000088615a89565b61425d919061583e565b115b1561427757614272898d8d87878f614c98565b614305565b89156142c35760405167ffffffffffffffff8c811682528d16907f8340aa7a5b37153230f8b64fa66f25c843e5002c60e63a25db6a9195005ccabd9060200160405180910390a2614305565b60405167ffffffffffffffff8c811682528d16907f31d16d882c6405d327fa305ecf0d52b45154868e0828822533fd2547f4b21a759060200160405180910390a25b505050600390950180547fffffffffffffffffffffffffffffffffffffffffffffff00000000000000000016680100000000000000001790555050505050505050565b73ffffffffffffffffffffffffffffffffffffffff831660009081526074602052604090205482146143fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4f70657261746f7220646f6573206e6f7420706572666f726d2074686520726560448201527f7175657374656420726f6c6500000000000000000000000000000000000000006064820152608401610ab3565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001820160205260409020541561443357614433838261457f565b73ffffffffffffffffffffffffffffffffffffffff83166000908152607260209081526040808320546fffffffffffffffffffffffffffffffff168352607390915290206144819084613f69565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260726020908152604080832080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169055607482528083209290925590519182527f80c0b871b97b595b16a7741c1b06fed0c6f6f558639f18ccbce50724325dc40d9101611568565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6145898183613f69565b5073ffffffffffffffffffffffffffffffffffffffff82166000908152607260209081526040808320546fffffffffffffffffffffffffffffffff90811680855260759093529083208054929392909116916145e483615ac6565b82546101009290920a6fffffffffffffffffffffffffffffffff81810219909316918316021790915582811660009081526075602052604081205490911690039050610ae8576065546040517fad9e91ee0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8316600482015243602482015273ffffffffffffffffffffffffffffffffffffffff9091169063ad9e91ee90604401600060405180830381600087803b1580156146ad57600080fd5b505af11580156146c1573d6000803e3d6000fd5b50505050505050565b600383015468010000000000000000900460ff1615614745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53657373696f6e207375626d697373696f6e73206861766520636c6f736564006044820152606401610ab3565b6000846002015460675486600101544361475f9190615b10565b6147699190615a89565b614773919061583e565b855461477f9190615a71565b60038601549091506000906fffffffffffffffffffffffffffffffff168210156147aa5760006147cb565b60038601546147cb906fffffffffffffffffffffffffffffffff1683615b10565b90508867ffffffffffffffff16811115801561481157506003860154614803906fffffffffffffffffffffffffffffffff1683615a71565b8967ffffffffffffffff1611155b61489d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f426c6f636b20686569676874206973206f7574206f6620626f756e647320666f60448201527f72206c6976652073796e630000000000000000000000000000000000000000006064820152608401610ab3565b6069546148b49067ffffffffffffffff1643615a71565b6003860180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92909216919091179055606554336000908152607260205260408082205490517f4c4a17090000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201529091829173ffffffffffffffffffffffffffffffffffffffff90911690634c4a1709906024016040805180830381865afa158015614983573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149a7919061594c565b91509150856149ca57607b546fffffffffffffffffffffffffffffffff166149f4565b60685470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff165b6fffffffffffffffffffffffffffffffff16826fffffffffffffffffffffffffffffffff161015614a81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f496e73756666696369656e746c79207374616b656420746f207375626d6974006044820152606401610ab3565b614a8b818361597b565b85546fffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116178655600188810180548083018255600091825260208083209091018e90558d82528a8152604080832080850180548087018255908552838520018f90558e8452808352908320805494850181558352912090910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790558654909170010000000000000000000000000000000090910416866010614b68836159af565b82546fffffffffffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550600388015460405167ffffffffffffffff9182168152818e16918f16907f8b1f889addbfa41db5227bae3b091bd5c8b9a9122f874dfe54ba2f75aabe1f4c9060200160405180910390a350505050505050505050505050565b606081600001805480602002602001604051908101604052809291908181526020018280548015614c3d57602002820191906000526020600020905b815481526020019060010190808311614c29575b50505050509050919050565b6000818152600183016020526040812054614c9057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611bae565b506000611bae565b60008381526020878152604080832085845290915281208054828167ffffffffffffffff811115614ccb57614ccb615b27565b604051908082528060200260200182016040528015614cf4578160200160208202803683370190505b50905060008267ffffffffffffffff811115614d1257614d12615b27565b604051908082528060200260200182016040528015614d3b578160200160208202803683370190505b509050600060028c01815b85811015614dc557816000888381548110614d6357614d636158e5565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902054614db1906fffffffffffffffffffffffffffffffff168461597b565b925080614dbd81615914565b915050614d46565b5060005b85811015614eef57868181548110614de357614de36158e5565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1680835284825260408084206072909352909220548751929a5090916fffffffffffffffffffffffffffffffff90911690879084908110614e4957614e496158e5565b6fffffffffffffffffffffffffffffffff9283166020918202929092010152606854825486831692614e7e9281169116615a89565b614e88919061583e565b858381518110614e9a57614e9a6158e5565b6fffffffffffffffffffffffffffffffff92831660209182029290920101528154700100000000000000000000000000000000900416600103614edc57600081555b5080614ee781615914565b915050614dc9565b506065546040517f605a501700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063605a501790614f489087908790600401615b98565b600060405180830381600087803b158015614f6257600080fd5b505af1158015614f76573d6000803e3d6000fd5b505050508715614fd557898b67ffffffffffffffff168d67ffffffffffffffff167ff05ac779af1ec75a7b2fbe9415b33a67c00294a121786f7ce2eb3f92e4a6424a8c604051614fc891815260200190565b60405180910390a4615026565b898b67ffffffffffffffff168d67ffffffffffffffff167f93dcf9329a330cb95723152c05719560f2fbd50e215c542854b27acc80c9108d8c60405161501d91815260200190565b60405180910390a45b60008a815260208e905260408120906150426001830182615288565b505050505050505050505050505050565b600054610100900460ff166150ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ab3565b6118f833614508565b600081815260018301602052604081205480156151dc576000615117600183615b10565b855490915060009061512b90600190615b10565b905081811461519057600086600001828154811061514b5761514b6158e5565b906000526020600020015490508087600001848154811061516e5761516e6158e5565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806151a1576151a1615bc6565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611bae565b6000915050611bae565b8280546151f29061586b565b90600052602060002090601f0160209004810192826152145760008555615278565b82601f1061524b578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555615278565b82800160010185558215615278579182015b8281111561527857823582559160200191906001019061525d565b506152849291506152a2565b5090565b50805460008255906000526020600020908101906118e391905b5b8082111561528457600081556001016152a3565b73ffffffffffffffffffffffffffffffffffffffff811681146118e357600080fd5b6000602082840312156152eb57600080fd5b813561383d816152b7565b803567ffffffffffffffff8116811461530e57600080fd5b919050565b60008060008060008060a0878903121561532c57600080fd5b615335876152f6565b9550615343602088016152f6565b94506040870135935060608701359250608087013567ffffffffffffffff8082111561536e57600080fd5b818901915089601f83011261538257600080fd5b81358181111561539157600080fd5b8a60208285010111156153a357600080fd5b6020830194508093505050509295509295509295565b600081518084526020808501945080840160005b838110156153ff57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016153cd565b509495945050505050565b6fffffffffffffffffffffffffffffffff8316815260406020820152600061543560408301846153b9565b949350505050565b6fffffffffffffffffffffffffffffffff811681146118e357600080fd5b6000806040838503121561546e57600080fd5b8235615479816152b7565b915060208301356154898161543d565b809150509250929050565b600080604083850312156154a757600080fd5b6154b0836152f6565b91506154be602084016152f6565b90509250929050565b6000602082840312156154d957600080fd5b61383d826152f6565b600080600080608085870312156154f857600080fd5b615501856152f6565b935061550f602086016152f6565b93969395505050506040820135916060013590565b60006020828403121561553657600080fd5b5035919050565b6000806040838503121561555057600080fd5b823561555b816152b7565b91506020830135615489816152b7565b60006020828403121561557d57600080fd5b813561383d8161543d565b6000806000806080858703121561559e57600080fd5b6155a7856152f6565b966020860135965060408601359560600135945092505050565b600080604083850312156155d457600080fd5b82356155df8161543d565b946020939093013593505050565b6000806000806080858703121561560357600080fd5b61560c856152f6565b935061561a602086016152f6565b92506040850135801515811461562f57600080fd5b9150606085013561563f816152b7565b939692955090935050565b60208152600061383d60208301846153b9565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b83811015615726577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc089870301855282518051808852835b818110156156d8578281018a01518982018b015289016156bd565b818111156156e857848a838b0101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01696909601870195509386019391860191600101615685565b509398975050505050505050565b60808152600061574760808301876153b9565b828103602084015261575981876153b9565b9050828103604084015261576d81866153b9565b9050828103606084015261578181856153b9565b979650505050505050565b600080600080608085870312156157a257600080fd5b84516157ad816152b7565b60208601519094506157be8161543d565b60408601519093506157cf8161543d565b606086015190925061563f8161543d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008261584d5761584d6157e0565b500490565b60006020828403121561586457600080fd5b5051919050565b600181811c9082168061587f57607f821691505b6020821081036158b8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600067ffffffffffffffff808416806158d9576158d96157e0565b92169190910692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036159455761594561580f565b5060010190565b6000806040838503121561595f57600080fd5b825161596a8161543d565b60208401519092506154898161543d565b60006fffffffffffffffffffffffffffffffff8083168185168083038211156159a6576159a661580f565b01949350505050565b60006fffffffffffffffffffffffffffffffff8083168181036159d4576159d461580f565b6001019392505050565b600067ffffffffffffffff808a16835280891660208401525086604083015285606083015260c060808301528360c0830152838560e0840137600060e0858401015260e07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190506fffffffffffffffffffffffffffffffff831660a083015298975050505050505050565b60008219821115615a8457615a8461580f565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615ac157615ac161580f565b500290565b60006fffffffffffffffffffffffffffffffff821680615ae857615ae861580f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b600082821015615b2257615b2261580f565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600081518084526020808501945080840160005b838110156153ff5781516fffffffffffffffffffffffffffffffff1687529582019590820190600101615b6a565b604081526000615bab6040830185615b56565b8281036020840152615bbd8185615b56565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122041e122264febe9cb1132e567c7c7d3cf185391d6bed515aae745570a761b967164736f6c634300080d0033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading