Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- StateConnector
- Optimization enabled
- true
- Compiler version
- v0.7.6+commit.7338295f
- Optimization runs
- 200
- Verified at
- 2022-07-13T20:49:30.263090Z
./contracts/genesis/implementation/StateConnector.sol
// (c) 2021, Flare Networks Limited. All rights reserved. // Please see the file LICENSE for licensing terms. // SPDX-License-Identifier: MIT pragma solidity 0.7.6; contract StateConnector { //==================================================================== // Data Structures //==================================================================== // unused old storage slots (genesis contract upgrade) uint256[16] private gap; // Signalling block.coinbase value address public constant SIGNAL_COINBASE = address(0x00000000000000000000000000000000000DEaD1); // November 5th, 2021 uint256 public constant BUFFER_TIMESTAMP_OFFSET = 1636070400 seconds; // Amount of time a buffer is active before cycling to the next one uint256 public constant BUFFER_WINDOW = 90 seconds; // {Requests, Votes, Reveals} uint256 public constant TOTAL_STORED_BUFFERS = 3; // Store a proof for one week uint256 public constant TOTAL_STORED_PROOFS = (1 weeks) / BUFFER_WINDOW; // Cold wallet address => Hot wallet address mapping(address => address) public attestorAddressMapping; //======================= // VOTING DATA STRUCTURES //======================= // Voting round consists of 4 sequential buffer windows: collect, commit, reveal, finalize // Round ID is the buffer number of the window of the collect phase struct Vote { // Struct for Vote in buffer number 'N' // Hash of the Merkle root (+ random number and msg.sender) that contains valid requests from 'Round ID = N-1' bytes32 commitHash; // Merkle root for 'Round ID = N-2' used for commitHash in buffer number 'N-1' bytes32 merkleRoot; // Random number for 'Round ID = N-2' used for commitHash in buffer number 'N-1' bytes32 randomNumber; } struct Buffers { // {Requests, Votes, Reveals} Vote[TOTAL_STORED_BUFFERS] votes; // The latest buffer number that this account has voted on, used for determining relevant votes uint256 latestVote; } mapping(address => Buffers) public buffers; //============================= // MERKLE PROOF DATA STRUCTURES //============================= // The total number of buffers that have elapsed over time such that the latest buffer // has been proven using finaliseRound() uint256 public totalBuffers; // The proven merkle roots for each Round ID, // accessed using: Round ID % TOTAL_STORED_PROOFS // within one week of proving the merkle root. bytes32[TOTAL_STORED_PROOFS] public merkleRoots; //==================================================================== // Events //==================================================================== event AttestationRequest( address sender, uint256 timestamp, bytes data ); event RoundFinalised( uint256 indexed roundId, bytes32 merkleRoot ); //==================================================================== // Constructor //==================================================================== constructor() { /* empty block */ } //==================================================================== // Functions //==================================================================== function updateAttestorAddressMapping(address _updatedAddress) external { attestorAddressMapping[msg.sender] = _updatedAddress; } function requestAttestations(bytes calldata _data) external { emit AttestationRequest(msg.sender, block.timestamp, _data); } function submitAttestation( uint256 _bufferNumber, bytes32 _commitHash, bytes32 _merkleRoot, bytes32 _randomNumber ) external returns ( bool _isInitialBufferSlot ) { require(_bufferNumber == (block.timestamp - BUFFER_TIMESTAMP_OFFSET) / BUFFER_WINDOW, "wrong bufferNumber"); buffers[msg.sender].latestVote = _bufferNumber; buffers[msg.sender].votes[_bufferNumber % TOTAL_STORED_BUFFERS] = Vote( _commitHash, _merkleRoot, _randomNumber ); // Determine if this is the first attestation submitted in a new buffer round. // If so, the golang code will automatically finalise the previous round using finaliseRound() if (_bufferNumber > totalBuffers) { return true; } return false; } function getAttestation(uint256 _bufferNumber) external view returns (bytes32 _merkleRoot) { address attestor = attestorAddressMapping[msg.sender]; if (attestor == address(0)) { attestor = msg.sender; } require(_bufferNumber > 1); uint256 prevBufferNumber = _bufferNumber - 1; require(buffers[attestor].latestVote >= prevBufferNumber); bytes32 commitHash = buffers[attestor].votes[(prevBufferNumber - 1) % TOTAL_STORED_BUFFERS].commitHash; _merkleRoot = buffers[attestor].votes[prevBufferNumber % TOTAL_STORED_BUFFERS].merkleRoot; bytes32 randomNumber = buffers[attestor].votes[prevBufferNumber % TOTAL_STORED_BUFFERS].randomNumber; require(commitHash == keccak256(abi.encode(_merkleRoot, randomNumber, attestor))); } function finaliseRound(uint256 _bufferNumber, bytes32 _merkleRoot) external { require(_bufferNumber > 3); require(_bufferNumber == (block.timestamp - BUFFER_TIMESTAMP_OFFSET) / BUFFER_WINDOW); require(_bufferNumber > totalBuffers); // The following region can only be called from the golang code if (msg.sender == block.coinbase && block.coinbase == SIGNAL_COINBASE) { totalBuffers = _bufferNumber; merkleRoots[(_bufferNumber - 3) % TOTAL_STORED_PROOFS] = _merkleRoot; emit RoundFinalised(_bufferNumber - 3, _merkleRoot); } } function lastFinalizedRoundId() external view returns (uint256 _roundId) { require(totalBuffers >= 3, "totalBuffers < 3"); return totalBuffers - 3; } function merkleRoot(uint256 _roundId) external view returns (bytes32) { require(totalBuffers >= 3, "totalBuffers < 3"); require(_roundId <= totalBuffers - 3, "not finalized"); require(_roundId < TOTAL_STORED_PROOFS || _roundId > totalBuffers - 3 - TOTAL_STORED_PROOFS, "expired"); return merkleRoots[_roundId % TOTAL_STORED_PROOFS]; } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"AttestationRequest","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"RoundFinalised","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256","indexed":true},{"type":"bytes32","name":"merkleRoot","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BUFFER_TIMESTAMP_OFFSET","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BUFFER_WINDOW","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"SIGNAL_COINBASE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"TOTAL_STORED_BUFFERS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"TOTAL_STORED_PROOFS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"attestorAddressMapping","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"latestVote","internalType":"uint256"}],"name":"buffers","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"finaliseRound","inputs":[{"type":"uint256","name":"_bufferNumber","internalType":"uint256"},{"type":"bytes32","name":"_merkleRoot","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"_merkleRoot","internalType":"bytes32"}],"name":"getAttestation","inputs":[{"type":"uint256","name":"_bufferNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_roundId","internalType":"uint256"}],"name":"lastFinalizedRoundId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"merkleRoot","inputs":[{"type":"uint256","name":"_roundId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"merkleRoots","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestAttestations","inputs":[{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"_isInitialBufferSlot","internalType":"bool"}],"name":"submitAttestation","inputs":[{"type":"uint256","name":"_bufferNumber","internalType":"uint256"},{"type":"bytes32","name":"_commitHash","internalType":"bytes32"},{"type":"bytes32","name":"_merkleRoot","internalType":"bytes32"},{"type":"bytes32","name":"_randomNumber","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalBuffers","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateAttestorAddressMapping","inputs":[{"type":"address","name":"_updatedAddress","internalType":"address"}]}]
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101005760003560e01c8063c2f56d4c11610097578063ec7424a011610066578063ec7424a014610284578063f417c9d81461028c578063f5f59a4a14610294578063f64b6fda1461029c57610100565b8063c2f56d4c146101f0578063cfd1fdad14610216578063dd86215714610259578063eaebf6d31461026157610100565b80635f8c940d116100d35780635f8c940d1461018157806371c5ecb11461018957806371e24574146101a65780637ff6faa6146101cc57610100565b8063273c463b1461010557806329be4db21461012d5780633c70b3571461015c5780634b8a125f14610179575b600080fd5b61012b6004803603602081101561011b57600080fd5b50356001600160a01b031661030c565b005b61014a6004803603602081101561014357600080fd5b503561033b565b60408051918252519081900360200190f35b61014a6004803603602081101561017257600080fd5b503561049a565b61014a61059c565b61014a6105a4565b61014a6004803603602081101561019f57600080fd5b50356105a9565b61014a600480360360208110156101bc57600080fd5b50356001600160a01b03166105c1565b6101d46105d6565b604080516001600160a01b039092168252519081900360200190f35b6101d46004803603602081101561020657600080fd5b50356001600160a01b03166105dd565b6102456004803603608081101561022c57600080fd5b50803590602081013590604081013590606001356105f8565b604080519115158252519081900360200190f35b61014a6106d4565b61012b6004803603604081101561027757600080fd5b508035906020013561072c565b61014a6107d0565b61014a6107d6565b61014a6107dc565b61012b600480360360208110156102b257600080fd5b8101906020810181356401000000008111156102cd57600080fd5b8201836020820111156102df57600080fd5b8035906020019184600183028401116401000000008311171561030157600080fd5b5090925090506107e1565b33600090815260106020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b336000908152601060205260408120546001600160a01b03168061035c5750335b6001831161036957600080fd5b6001600160a01b03811660009081526011602052604090206009015460001984019081111561039757600080fd5b6001600160a01b03821660009081526011602052604081206003600019840106600381106103c157fe5b600390810291909101546001600160a01b0385166000908152601160205260409020909250908306600381106103f357fe5b60030201600101549350600060116000856001600160a01b03166001600160a01b031681526020019081526020016000206000016003848161043157fe5b066003811061043c57fe5b6003020160020154905084818560405160200180848152602001838152602001826001600160a01b03168152602001935050505060405160208183030381529060405280519060200120821461049157600080fd5b50505050919050565b6000600360125410156104e7576040805162461bcd60e51b815260206004820152601060248201526f746f74616c42756666657273203c203360801b604482015290519081900360640190fd5b600360125403821115610531576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd08199a5b985b1a5e9959609a1b604482015290519081900360640190fd5b611a408210806105475750601254611a42190182115b610582576040805162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b604482015290519081900360640190fd5b6013611a408306611a40811061059457fe5b015492915050565b636184740081565b600381565b601381611a4081106105ba57600080fd5b0154905081565b60116020526000908152604090206009015481565b620dead181565b6010602052600090815260409020546001600160a01b031681565b6000605a63618473ff19420104851461064d576040805162461bcd60e51b81526020600482015260126024820152713bb937b73390313ab33332b9273ab6b132b960711b604482015290519081900360640190fd5b336000818152601160208181526040808420600981018b905581516060810183528a81528084018a9052918201889052949093525290600387066003811061069157fe5b600302016000820151816000015560208201518160010155604082015181600201559050506012548511156106c8575060016106cc565b5060005b949350505050565b600060036012541015610721576040805162461bcd60e51b815260206004820152601060248201526f746f74616c42756666657273203c203360801b604482015290519081900360640190fd5b506012546002190190565b6003821161073957600080fd5b605a63618473ff19420104821461074f57600080fd5b601254821161075d57600080fd5b334114801561076e575041620dead1145b156107cc576012829055806013611a40600219850106611a40811061078f57fe5b01556040805182815290516002198401917f8ffd19aa79a62d0764e560d21b1245698310783be781d7d80b38233d4d7d288c919081900360200190a25b5050565b60125481565b611a4081565b605a81565b7f7cbc6812801238dea8eb58356bb62b95dbce8dc28498aa30e7d2c6873ed36cc73342848460405180856001600160a01b03168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a1505056fea26469706673582212201835668a4aedf7b8dd6cb953219e7b126f41acff165aaa41023acd8f3dd8edf064736f6c63430007060033