diff --git a/contracts/src/bridge/ISequencerInbox.sol b/contracts/src/bridge/ISequencerInbox.sol index d801dca356..994c7c0126 100644 --- a/contracts/src/bridge/ISequencerInbox.sol +++ b/contracts/src/bridge/ISequencerInbox.sol @@ -69,6 +69,8 @@ interface ISequencerInbox is IDelayedMessageProvider { function isBatchPoster(address) external view returns (bool); + function isSequencer(address) external view returns (bool); + struct DasKeySetInfo { bool isValidKeyset; uint64 creationBlock; @@ -154,6 +156,14 @@ interface ISequencerInbox is IDelayedMessageProvider { */ function invalidateKeysetHash(bytes32 ksHash) external; + /** + * @notice Updates whether an address is authorized to be a sequencer. + * @dev The IsSequencer information is used only off-chain by the nitro node to validate sequencer feed signer. + * @param addr the address + * @param isSequencer_ if the specified address should be authorized as a sequencer + */ + function setIsSequencer(address addr, bool isSequencer_) external; + // ---------- initializer ---------- function initialize(IBridge bridge_, MaxTimeVariation calldata maxTimeVariation_) external; diff --git a/contracts/src/bridge/SequencerInbox.sol b/contracts/src/bridge/SequencerInbox.sol index 5072359b09..c95cd70b72 100644 --- a/contracts/src/bridge/SequencerInbox.sol +++ b/contracts/src/bridge/SequencerInbox.sol @@ -64,6 +64,8 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox uint256 internal immutable deployTimeChainId = block.chainid; + mapping(address => bool) public isSequencer; + function _chainIdChanged() internal view returns (bool) { return deployTimeChainId != block.chainid; } @@ -450,6 +452,12 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox emit OwnerFunctionCalled(3); } + /// @inheritdoc ISequencerInbox + function setIsSequencer(address addr, bool isSequencer_) external onlyRollupOwner { + isSequencer[addr] = isSequencer_; + emit OwnerFunctionCalled(4); + } + function isValidKeysetHash(bytes32 ksHash) external view returns (bool) { return dasKeySetInfo[ksHash].isValidKeyset; } diff --git a/contracts/test/storage/SequencerInbox.dot b/contracts/test/storage/SequencerInbox.dot index 81ca079da4..f9ea05abe5 100644 --- a/contracts/test/storage/SequencerInbox.dot +++ b/contracts/test/storage/SequencerInbox.dot @@ -4,7 +4,7 @@ rankdir=LR color=black arrowhead=open node [shape=record, style=filled, fillcolor=gray95 fontname="Courier New"] -3 [label="SequencerInbox \<\\>\n | {{ slot| 0 | 1 | 2 | 3 | 4-7 | 8 } | { type: \.variable (bytes) | { uint256: totalDelayedMessagesRead (32) } | { unallocated (12) | IBridge: bridge (20) } | { unallocated (12) | IOwnable: rollup (20) } | { mapping\(address=\>bool\): isBatchPoster (32) } | { <9> ISequencerInbox.MaxTimeVariation: maxTimeVariation (128) } | { <12> mapping\(bytes32=\>DasKeySetInfo\): dasKeySetInfo (32) }}}"] +3 [label="SequencerInbox \<\\>\n | {{ slot| 0 | 1 | 2 | 3 | 4-7 | 8 | 9 } | { type: \.variable (bytes) | { uint256: totalDelayedMessagesRead (32) } | { unallocated (12) | IBridge: bridge (20) } | { unallocated (12) | IOwnable: rollup (20) } | { mapping\(address=\>bool\): isBatchPoster (32) } | { <9> ISequencerInbox.MaxTimeVariation: maxTimeVariation (128) } | { <12> mapping\(bytes32=\>DasKeySetInfo\): dasKeySetInfo (32) } | { mapping\(address=\>bool\): isSequencer (32) }}}"] 1 [label="ISequencerInbox.MaxTimeVariation \<\\>\n | {{ slot| 4 | 5 | 6 | 7 } | { type: variable (bytes) | { uint256: MaxTimeVariation.delayBlocks (32) } | { uint256: MaxTimeVariation.futureBlocks (32) } | { uint256: MaxTimeVariation.delaySeconds (32) } | { uint256: MaxTimeVariation.futureSeconds (32) }}}"]