-
Notifications
You must be signed in to change notification settings - Fork 3.2k
/
SystemConfig.sol
255 lines (223 loc) · 11.3 KB
/
SystemConfig.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { ISemver } from "src/universal/ISemver.sol";
import { ResourceMetering } from "src/L1/ResourceMetering.sol";
import { Storage } from "src/libraries/Storage.sol";
import { Constants } from "src/libraries/Constants.sol";
/// @title SystemConfig
/// @notice The SystemConfig contract is used to manage configuration of an Optimism network.
/// All configuration is stored on L1 and picked up by L2 as part of the derviation of
/// the L2 chain.
contract SystemConfig is OwnableUpgradeable, ISemver {
/// @notice Enum representing different types of updates.
/// @custom:value BATCHER Represents an update to the batcher hash.
/// @custom:value GAS_CONFIG Represents an update to txn fee config on L2.
/// @custom:value GAS_LIMIT Represents an update to gas limit on L2.
/// @custom:value UNSAFE_BLOCK_SIGNER Represents an update to the signer key for unsafe
/// block distrubution.
enum UpdateType {
BATCHER,
GAS_CONFIG,
GAS_LIMIT,
UNSAFE_BLOCK_SIGNER
}
/// @notice Version identifier, used for upgrades.
uint256 public constant VERSION = 0;
/// @notice Storage slot that the unsafe block signer is stored at.
/// Storing it at this deterministic storage slot allows for decoupling the storage
/// layout from the way that `solc` lays out storage. The `op-node` uses a storage
/// proof to fetch this value.
/// @dev NOTE: this value will be migrated to another storage slot in a future version.
/// User input should not be placed in storage in this contract until this migration
/// happens. It is unlikely that keccak second preimage resistance will be broken,
/// but it is better to be safe than sorry.
bytes32 public constant UNSAFE_BLOCK_SIGNER_SLOT = keccak256("systemconfig.unsafeblocksigner");
/// @notice Fixed L2 gas overhead. Used as part of the L2 fee calculation.
uint256 public overhead;
/// @notice Dynamic L2 gas overhead. Used as part of the L2 fee calculation.
uint256 public scalar;
/// @notice Identifier for the batcher.
/// For version 1 of this configuration, this is represented as an address left-padded
/// with zeros to 32 bytes.
bytes32 public batcherHash;
/// @notice L2 block gas limit.
uint64 public gasLimit;
/// @notice The configuration for the deposit fee market.
/// Used by the OptimismPortal to meter the cost of buying L2 gas on L1.
/// Set as internal with a getter so that the struct is returned instead of a tuple.
ResourceMetering.ResourceConfig internal _resourceConfig;
/// @notice Emitted when configuration is updated.
/// @param version SystemConfig version.
/// @param updateType Type of update.
/// @param data Encoded update data.
event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
/// @notice Semantic version.
/// @custom:semver 1.11.0
string public constant version = "1.11.0";
/// @notice Constructs the SystemConfig contract. Cannot set
/// the owner to `address(0)` due to the Ownable contract's
/// implementation, so set it to `address(0xdEaD)`
/// @param _owner Initial owner of the contract.
/// @param _overhead Initial overhead value.
/// @param _scalar Initial scalar value.
/// @param _batcherHash Initial batcher hash.
/// @param _gasLimit Initial gas limit.
/// @param _unsafeBlockSigner Initial unsafe block signer address.
/// @param _config Initial resource config.
constructor(
address _owner,
uint256 _overhead,
uint256 _scalar,
bytes32 _batcherHash,
uint64 _gasLimit,
address _unsafeBlockSigner,
ResourceMetering.ResourceConfig memory _config
) {
initialize({
_owner: _owner,
_overhead: _overhead,
_scalar: _scalar,
_batcherHash: _batcherHash,
_gasLimit: _gasLimit,
_unsafeBlockSigner: _unsafeBlockSigner,
_config: _config
});
}
/// @notice Initializer.
/// The resource config must be set before the require check.
/// @param _owner Initial owner of the contract.
/// @param _overhead Initial overhead value.
/// @param _scalar Initial scalar value.
/// @param _batcherHash Initial batcher hash.
/// @param _gasLimit Initial gas limit.
/// @param _unsafeBlockSigner Initial unsafe block signer address.
/// @param _config Initial ResourceConfig.
function initialize(
address _owner,
uint256 _overhead,
uint256 _scalar,
bytes32 _batcherHash,
uint64 _gasLimit,
address _unsafeBlockSigner,
ResourceMetering.ResourceConfig memory _config
)
public
initializer
{
__Ownable_init();
transferOwnership(_owner);
// These are set in ascending order of their UpdateTypes.
_setBatcherHash(_batcherHash);
_setGasConfig({ _overhead: _overhead, _scalar: _scalar });
_setGasLimit(_gasLimit);
_setUnsafeBlockSigner(_unsafeBlockSigner);
_setResourceConfig(_config);
require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low");
}
/// @notice Returns the minimum L2 gas limit that can be safely set for the system to
/// operate. The L2 gas limit must be larger than or equal to the amount of
/// gas that is allocated for deposits per block plus the amount of gas that
/// is allocated for the system transaction.
/// This function is used to determine if changes to parameters are safe.
/// @return uint64 Minimum gas limit.
function minimumGasLimit() public view returns (uint64) {
return uint64(_resourceConfig.maxResourceLimit) + uint64(_resourceConfig.systemTxMaxGas);
}
/// @notice High level getter for the unsafe block signer address.
/// Unsafe blocks can be propagated across the p2p network if they are signed by the
/// key corresponding to this address.
/// @return addr_ Address of the unsafe block signer.
// solhint-disable-next-line ordering
function unsafeBlockSigner() public view returns (address addr_) {
addr_ = Storage.getAddress(UNSAFE_BLOCK_SIGNER_SLOT);
}
/// @notice Updates the unsafe block signer address. Can only be called by the owner.
/// @param _unsafeBlockSigner New unsafe block signer address.
function setUnsafeBlockSigner(address _unsafeBlockSigner) external onlyOwner {
_setUnsafeBlockSigner(_unsafeBlockSigner);
}
/// @notice Updates the unsafe block signer address.
/// @param _unsafeBlockSigner New unsafe block signer address.
function _setUnsafeBlockSigner(address _unsafeBlockSigner) internal {
Storage.setAddress(UNSAFE_BLOCK_SIGNER_SLOT, _unsafeBlockSigner);
bytes memory data = abi.encode(_unsafeBlockSigner);
emit ConfigUpdate(VERSION, UpdateType.UNSAFE_BLOCK_SIGNER, data);
}
/// @notice Updates the batcher hash. Can only be called by the owner.
/// @param _batcherHash New batcher hash.
function setBatcherHash(bytes32 _batcherHash) external onlyOwner {
_setBatcherHash(_batcherHash);
}
/// @notice Internal function for updating the batcher hash.
/// @param _batcherHash New batcher hash.
function _setBatcherHash(bytes32 _batcherHash) internal {
batcherHash = _batcherHash;
bytes memory data = abi.encode(_batcherHash);
emit ConfigUpdate(VERSION, UpdateType.BATCHER, data);
}
/// @notice Updates gas config. Can only be called by the owner.
/// @param _overhead New overhead value.
/// @param _scalar New scalar value.
function setGasConfig(uint256 _overhead, uint256 _scalar) external onlyOwner {
_setGasConfig(_overhead, _scalar);
}
/// @notice Internal function for updating the gas config.
/// @param _overhead New overhead value.
/// @param _scalar New scalar value.
function _setGasConfig(uint256 _overhead, uint256 _scalar) internal {
overhead = _overhead;
scalar = _scalar;
bytes memory data = abi.encode(_overhead, _scalar);
emit ConfigUpdate(VERSION, UpdateType.GAS_CONFIG, data);
}
/// @notice Updates the L2 gas limit. Can only be called by the owner.
/// @param _gasLimit New gas limit.
function setGasLimit(uint64 _gasLimit) external onlyOwner {
_setGasLimit(_gasLimit);
}
/// @notice Internal function for updating the L2 gas limit.
/// @param _gasLimit New gas limit.
function _setGasLimit(uint64 _gasLimit) internal {
require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low");
gasLimit = _gasLimit;
bytes memory data = abi.encode(_gasLimit);
emit ConfigUpdate(VERSION, UpdateType.GAS_LIMIT, data);
}
/// @notice A getter for the resource config.
/// Ensures that the struct is returned instead of a tuple.
/// @return ResourceConfig
function resourceConfig() external view returns (ResourceMetering.ResourceConfig memory) {
return _resourceConfig;
}
/// @notice An external setter for the resource config.
/// In the future, this method may emit an event that the `op-node` picks up
/// for when the resource config is changed.
/// @param _config The new resource config values.
function setResourceConfig(ResourceMetering.ResourceConfig memory _config) external onlyOwner {
_setResourceConfig(_config);
}
/// @notice An internal setter for the resource config.
/// Ensures that the config is sane before storing it by checking for invariants.
/// @param _config The new resource config.
function _setResourceConfig(ResourceMetering.ResourceConfig memory _config) internal {
// Min base fee must be less than or equal to max base fee.
require(
_config.minimumBaseFee <= _config.maximumBaseFee, "SystemConfig: min base fee must be less than max base"
);
// Base fee change denominator must be greater than 1.
require(_config.baseFeeMaxChangeDenominator > 1, "SystemConfig: denominator must be larger than 1");
// Max resource limit plus system tx gas must be less than or equal to the L2 gas limit.
// The gas limit must be increased before these values can be increased.
require(_config.maxResourceLimit + _config.systemTxMaxGas <= gasLimit, "SystemConfig: gas limit too low");
// Elasticity multiplier must be greater than 0.
require(_config.elasticityMultiplier > 0, "SystemConfig: elasticity multiplier cannot be 0");
// No precision loss when computing target resource limit.
require(
((_config.maxResourceLimit / _config.elasticityMultiplier) * _config.elasticityMultiplier)
== _config.maxResourceLimit,
"SystemConfig: precision loss with target resource limit"
);
_resourceConfig = _config;
}
}