1use anvil_zksync_config::types::SystemContractsOptions;
2use flate2::read::GzDecoder;
3use once_cell::sync::Lazy;
4use serde_json::Value;
5use std::collections::HashMap;
6use std::io::Read;
7use std::path::Path;
8use zksync_types::system_contracts::{
9 get_system_smart_contracts, get_system_smart_contracts_from_dir,
10};
11use zksync_types::{
12 block::DeployedContract, ProtocolVersionId, ACCOUNT_CODE_STORAGE_ADDRESS, BOOTLOADER_ADDRESS,
13 BOOTLOADER_UTILITIES_ADDRESS, CODE_ORACLE_ADDRESS, COMPLEX_UPGRADER_ADDRESS,
14 COMPRESSOR_ADDRESS, CONTRACT_DEPLOYER_ADDRESS, CREATE2_FACTORY_ADDRESS,
15 ECRECOVER_PRECOMPILE_ADDRESS, EC_ADD_PRECOMPILE_ADDRESS, EC_MUL_PRECOMPILE_ADDRESS,
16 EC_PAIRING_PRECOMPILE_ADDRESS, EVENT_WRITER_ADDRESS, EVM_GAS_MANAGER_ADDRESS,
17 EVM_HASHES_STORAGE_ADDRESS, EVM_PREDEPLOYS_MANAGER_ADDRESS, IDENTITY_ADDRESS,
18 IMMUTABLE_SIMULATOR_STORAGE_ADDRESS, KECCAK256_PRECOMPILE_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS,
19 L1_MESSENGER_ADDRESS, L2_ASSET_ROUTER_ADDRESS, L2_BASE_TOKEN_ADDRESS, L2_BRIDGEHUB_ADDRESS,
20 L2_GENESIS_UPGRADE_ADDRESS, L2_MESSAGE_ROOT_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS,
21 L2_WRAPPED_BASE_TOKEN_IMPL, MODEXP_PRECOMPILE_ADDRESS, MSG_VALUE_SIMULATOR_ADDRESS,
22 NONCE_HOLDER_ADDRESS, PUBDATA_CHUNK_PUBLISHER_ADDRESS, SECP256R1_VERIFY_PRECOMPILE_ADDRESS,
23 SHA256_PRECOMPILE_ADDRESS, SLOAD_CONTRACT_ADDRESS, SYSTEM_CONTEXT_ADDRESS,
24};
25use zksync_types::{AccountTreeId, Address, H160};
26
27pub const TIMESTAMP_ASSERTER_ADDRESS: Address = H160([
28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29 0x00, 0x80, 0x80, 0x12,
30]);
31
32static BUILTIN_CONTRACT_ARCHIVES: [(ProtocolVersionId, &[u8]); 3] = [
33 (
34 ProtocolVersionId::Version26,
35 include_bytes!("contracts/builtin-contracts-v26.tar.gz"),
36 ),
37 (
38 ProtocolVersionId::Version27,
39 include_bytes!("contracts/builtin-contracts-v27.tar.gz"),
40 ),
41 (
42 ProtocolVersionId::Version28,
43 include_bytes!("contracts/builtin-contracts-v28.tar.gz"),
44 ),
45];
46
47static BUILTIN_CONTRACT_ARTIFACTS: Lazy<HashMap<ProtocolVersionId, HashMap<String, Vec<u8>>>> =
48 Lazy::new(|| {
49 let mut result = HashMap::new();
50 for (protocol_version, built_in_contracts) in BUILTIN_CONTRACT_ARCHIVES {
51 let decoder = GzDecoder::new(built_in_contracts);
52 let mut archive = tar::Archive::new(decoder);
53 let mut contract_artifacts = HashMap::new();
54 for file in archive
55 .entries()
56 .expect("failed to decompress built-in contracts")
57 {
58 let mut file = file.expect("failed to read a built-in contract entry");
59 let path = file
60 .header()
61 .path()
62 .expect("contract path is malformed")
63 .file_name()
64 .expect("built-in contract entry does not have a filename")
65 .to_string_lossy()
66 .to_string();
67
68 let mut contents = Vec::with_capacity(
69 file.header().size().expect("contract size is corrupted") as usize,
70 );
71 file.read_to_end(&mut contents).unwrap();
72 contract_artifacts.insert(path, contents);
73 }
74 result.insert(protocol_version, contract_artifacts);
75 }
76 result
77 });
78
79pub fn bytecode_from_slice(artifact_name: &str, contents: &[u8]) -> Vec<u8> {
80 let artifact: Value = serde_json::from_slice(contents).expect(artifact_name);
81 let bytecode = artifact["bytecode"]
82 .as_object()
83 .unwrap_or_else(|| panic!("Bytecode not found in {:?}", artifact_name))
84 .get("object")
85 .unwrap_or_else(|| panic!("Bytecode object not found in {:?}", artifact_name))
86 .as_str()
87 .unwrap_or_else(|| panic!("Bytecode object is not a string in {:?}", artifact_name));
88
89 hex::decode(bytecode)
90 .unwrap_or_else(|err| panic!("Can't decode bytecode in {:?}: {}", artifact_name, err))
91}
92
93pub fn load_builtin_contract(protocol_version: ProtocolVersionId, artifact_name: &str) -> Vec<u8> {
94 let artifact_path = format!("{artifact_name}.json");
95 bytecode_from_slice(
96 artifact_name,
97 BUILTIN_CONTRACT_ARTIFACTS
98 .get(&protocol_version)
99 .unwrap_or_else(|| panic!("protocol version '{protocol_version}' is not supported"))
100 .get(&artifact_path)
101 .unwrap_or_else(|| {
102 panic!("failed to find built-in contract artifact at '{artifact_path}'")
103 }),
104 )
105}
106
107static BUILTIN_CONTRACTS: Lazy<HashMap<ProtocolVersionId, Vec<DeployedContract>>> =
109 Lazy::new(|| {
110 let mut result = HashMap::new();
111
112 for (protocol_version, _) in BUILTIN_CONTRACT_ARCHIVES {
113 let mut list = Vec::new();
114
115 list.extend(
117 BUILTIN_CONTRACT_LOCATIONS
118 .iter()
119 .filter(|(_, _, min_version)| &protocol_version >= min_version)
120 .map(|(artifact_name, address, _)| DeployedContract {
121 account_id: AccountTreeId::new(*address),
122 bytecode: load_builtin_contract(protocol_version, artifact_name),
123 }),
124 );
125
126 list.extend(
127 NON_KERNEL_CONTRACT_LOCATIONS
128 .iter()
129 .filter(|(_, _, min_version)| &protocol_version >= min_version)
130 .map(|(artifact_name, address, _)| DeployedContract {
131 account_id: AccountTreeId::new(*address),
132 bytecode: load_builtin_contract(protocol_version, artifact_name),
133 }),
134 );
135
136 result.insert(protocol_version, list);
137 }
138
139 result
140 });
141
142const V26: ProtocolVersionId = ProtocolVersionId::Version26;
143const V27: ProtocolVersionId = ProtocolVersionId::Version27;
144const V28: ProtocolVersionId = ProtocolVersionId::Version28;
145
146static BUILTIN_CONTRACT_LOCATIONS: [(&str, Address, ProtocolVersionId); 30] = [
148 ("AccountCodeStorage", ACCOUNT_CODE_STORAGE_ADDRESS, V26),
152 ("NonceHolder", NONCE_HOLDER_ADDRESS, V26),
153 ("KnownCodesStorage", KNOWN_CODES_STORAGE_ADDRESS, V26),
154 (
155 "ImmutableSimulator",
156 IMMUTABLE_SIMULATOR_STORAGE_ADDRESS,
157 V26,
158 ),
159 ("ContractDeployer", CONTRACT_DEPLOYER_ADDRESS, V26),
160 ("L1Messenger", L1_MESSENGER_ADDRESS, V26),
161 ("MsgValueSimulator", MSG_VALUE_SIMULATOR_ADDRESS, V26),
162 ("L2BaseToken", L2_BASE_TOKEN_ADDRESS, V26),
163 ("SystemContext", SYSTEM_CONTEXT_ADDRESS, V26),
164 ("BootloaderUtilities", BOOTLOADER_UTILITIES_ADDRESS, V26),
165 ("EventWriter", EVENT_WRITER_ADDRESS, V26),
166 ("Compressor", COMPRESSOR_ADDRESS, V26),
167 ("ComplexUpgrader", COMPLEX_UPGRADER_ADDRESS, V26),
168 (
169 "PubdataChunkPublisher",
170 PUBDATA_CHUNK_PUBLISHER_ADDRESS,
171 V26,
172 ),
173 ("EvmGasManager", EVM_GAS_MANAGER_ADDRESS, V27),
174 ("EvmPredeploysManager", EVM_PREDEPLOYS_MANAGER_ADDRESS, V27),
175 ("EvmHashesStorage", EVM_HASHES_STORAGE_ADDRESS, V27),
176 ("Keccak256", KECCAK256_PRECOMPILE_ADDRESS, V26),
180 ("SHA256", SHA256_PRECOMPILE_ADDRESS, V26),
181 ("Ecrecover", ECRECOVER_PRECOMPILE_ADDRESS, V26),
182 ("EcAdd", EC_ADD_PRECOMPILE_ADDRESS, V26),
183 ("EcMul", EC_MUL_PRECOMPILE_ADDRESS, V26),
184 ("EcPairing", EC_PAIRING_PRECOMPILE_ADDRESS, V26),
185 ("CodeOracle", CODE_ORACLE_ADDRESS, V26),
186 ("P256Verify", SECP256R1_VERIFY_PRECOMPILE_ADDRESS, V26),
187 ("Identity", IDENTITY_ADDRESS, V27),
188 ("Modexp", MODEXP_PRECOMPILE_ADDRESS, V28),
189 ("TimestampAsserter", TIMESTAMP_ASSERTER_ADDRESS, V26),
194 ("EmptyContract", Address::zero(), V26),
200 ("EmptyContract", BOOTLOADER_ADDRESS, V26),
201];
202
203pub static NON_KERNEL_CONTRACT_LOCATIONS: [(&str, Address, ProtocolVersionId); 8] = [
207 ("Create2Factory", CREATE2_FACTORY_ADDRESS, V26),
208 ("L2GenesisUpgrade", L2_GENESIS_UPGRADE_ADDRESS, V26),
209 ("Bridgehub", L2_BRIDGEHUB_ADDRESS, V26),
210 ("L2AssetRouter", L2_ASSET_ROUTER_ADDRESS, V26),
211 ("L2NativeTokenVault", L2_NATIVE_TOKEN_VAULT_ADDRESS, V26),
212 ("MessageRoot", L2_MESSAGE_ROOT_ADDRESS, V26),
213 ("SloadContract", SLOAD_CONTRACT_ADDRESS, V26),
214 ("L2WrappedBaseToken", L2_WRAPPED_BASE_TOKEN_IMPL, V26),
215];
216
217pub fn get_deployed_contracts(
218 options: SystemContractsOptions,
219 protocol_version: ProtocolVersionId,
220 system_contracts_path: Option<&Path>,
221) -> Vec<DeployedContract> {
222 match options {
223 SystemContractsOptions::BuiltIn | SystemContractsOptions::BuiltInWithoutSecurity => {
224 BUILTIN_CONTRACTS
225 .get(&protocol_version)
226 .unwrap_or_else(|| panic!("protocol version '{protocol_version}' is not supported"))
227 .clone()
228 }
229 SystemContractsOptions::Local => {
230 if let Some(path) = system_contracts_path {
232 get_system_smart_contracts_from_dir(path.to_path_buf())
233 } else {
234 get_system_smart_contracts()
235 }
236 }
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 fn count_protocol_contracts(protocol_version: ProtocolVersionId) -> usize {
245 let kernel_count = BUILTIN_CONTRACT_LOCATIONS
246 .iter()
247 .filter(|(_, _, min_version)| &protocol_version >= min_version)
248 .count();
249
250 let non_kernel_count = NON_KERNEL_CONTRACT_LOCATIONS
251 .iter()
252 .filter(|(_, _, min_version)| &protocol_version >= min_version)
253 .count();
254
255 kernel_count + non_kernel_count
256 }
257
258 #[test]
259 fn load_v26_contracts() {
260 let contracts = get_deployed_contracts(
261 SystemContractsOptions::BuiltIn,
262 ProtocolVersionId::Version26,
263 None,
264 );
265 assert_eq!(
266 contracts.len(),
267 count_protocol_contracts(ProtocolVersionId::Version26)
268 );
269 }
270
271 #[test]
272 fn load_v27_contracts() {
273 let contracts = get_deployed_contracts(
274 SystemContractsOptions::BuiltIn,
275 ProtocolVersionId::Version27,
276 None,
277 );
278 assert_eq!(
279 contracts.len(),
280 count_protocol_contracts(ProtocolVersionId::Version27)
281 );
282 }
283
284 #[test]
285 fn load_v28_contracts() {
286 let contracts = get_deployed_contracts(
287 SystemContractsOptions::BuiltIn,
288 ProtocolVersionId::Version28,
289 None,
290 );
291 assert_eq!(
292 contracts.len(),
293 count_protocol_contracts(ProtocolVersionId::Version28)
294 );
295 }
296}