This repository has been archived by the owner on Mar 25, 2024. It is now read-only.
/
KnownCodesStorage.sol
81 lines (69 loc) · 3.6 KB
/
KnownCodesStorage.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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {IKnownCodesStorage} from "./interfaces/IKnownCodesStorage.sol";
import {ISystemContract} from "./interfaces/ISystemContract.sol";
import {Utils} from "./libraries/Utils.sol";
import {SystemContractHelper} from "./libraries/SystemContractHelper.sol";
import {COMPRESSOR_CONTRACT, L1_MESSENGER_CONTRACT} from "./Constants.sol";
/**
* @author Matter Labs
* @custom:security-contact security@matterlabs.dev
* @notice The storage of this contract will basically serve as a mapping for the known code hashes.
* @dev Code hash is not strictly a hash, it's a structure where the first byte denotes the version of the hash,
* the second byte denotes whether the contract is constructed, and the next two bytes denote the length in 32-byte words.
* words. And then the next 28 bytes is the truncated hash.
*/
contract KnownCodesStorage is IKnownCodesStorage, ISystemContract {
modifier onlyCompressor() {
require(msg.sender == address(COMPRESSOR_CONTRACT), "Callable only by the compressor");
_;
}
/// @notice The method that is used by the bootloader to mark several bytecode hashes as known.
/// @param _shouldSendToL1 Whether the bytecode should be sent on L1.
/// @param _hashes Hashes of the bytecodes to be marked as known.
function markFactoryDeps(bool _shouldSendToL1, bytes32[] calldata _hashes) external onlyCallFromBootloader {
unchecked {
uint256 hashesLen = _hashes.length;
for (uint256 i = 0; i < hashesLen; ++i) {
_markBytecodeAsPublished(_hashes[i], _shouldSendToL1);
}
}
}
/// @notice The method used to mark a single bytecode hash as known.
/// @dev Only trusted contacts can call this method, currently only the bytecode compressor.
/// @param _bytecodeHash The hash of the bytecode that is marked as known.
function markBytecodeAsPublished(bytes32 _bytecodeHash) external onlyCompressor {
_markBytecodeAsPublished(_bytecodeHash, false);
}
/// @notice The method used to mark a single bytecode hash as known
/// @param _bytecodeHash The hash of the bytecode that is marked as known
/// @param _shouldSendToL1 Whether the bytecode should be sent on L1
function _markBytecodeAsPublished(bytes32 _bytecodeHash, bool _shouldSendToL1) internal {
if (getMarker(_bytecodeHash) == 0) {
_validateBytecode(_bytecodeHash);
if (_shouldSendToL1) {
L1_MESSENGER_CONTRACT.requestBytecodeL1Publication(_bytecodeHash);
}
// Save as known, to not resend the log to L1
assembly {
sstore(_bytecodeHash, 1)
}
emit MarkedAsKnown(_bytecodeHash, _shouldSendToL1);
}
}
/// @notice Returns the marker stored for a bytecode hash. 1 means that the bytecode hash is known
/// and can be used for deploying contracts. 0 otherwise.
function getMarker(bytes32 _hash) public view override returns (uint256 marker) {
assembly {
marker := sload(_hash)
}
}
/// @notice Validates the format of bytecodehash
/// @dev zk-circuit accepts & handles only valid format of bytecode hash, other input has undefined behavior
/// That's why we need to validate it
function _validateBytecode(bytes32 _bytecodeHash) internal pure {
uint8 version = uint8(_bytecodeHash[0]);
require(version == 1 && _bytecodeHash[1] == bytes1(0), "Incorrectly formatted bytecodeHash");
require(Utils.bytecodeLenInWords(_bytecodeHash) % 2 == 1, "Code length in words must be odd");
}
}