1fn resolve_builtin_call(expr: &Expression) -> Option<BuiltinCall> {
2 if let Expression::MemberAccess(_, inner, member) = expr {
3 if let Expression::Variable(base) = inner.as_ref() {
4 let member_name = member.name.as_str();
5 match base.name.as_str() {
6 "Runtime" => return resolve_runtime_member(member_name),
7 "abi" => return resolve_abi_member(member_name),
8 "Storage" => return resolve_storage_member(member_name),
9 "Syscalls" => return resolve_syscalls_member(member_name),
10 "NativeCalls" => return resolve_native_calls_member(member_name),
11 "Neo" => return resolve_neo_member(member_name),
12 "StdLib" => return resolve_stdlib_member(member_name),
23 "CryptoLib" => return resolve_cryptolib_member(member_name),
24 _ => {}
25 }
26 }
27 }
28
29 if let Expression::Variable(identifier) = expr {
30 if identifier.name == "ecrecover" {
31 return Some(BuiltinCall::Ecrecover);
32 }
33 if identifier.name == "keccak256" {
34 return Some(BuiltinCall::Keccak256);
35 }
36 if identifier.name == "sha256" {
47 return Some(BuiltinCall::NativeCall {
48 contract: NativeContract::CryptoLib,
49 method: "sha256".to_string(),
50 });
51 }
52 if identifier.name == "ripemd160" {
53 return Some(BuiltinCall::NativeCall {
54 contract: NativeContract::CryptoLib,
55 method: "ripemd160".to_string(),
56 });
57 }
58 if identifier.name == "type" {
59 return Some(BuiltinCall::TypeOf);
60 }
61 }
62
63 None
64}
65
66pub const BUILTIN_LIBRARY_BASES: &[&str] =
69 &["Runtime", "abi", "Storage", "Syscalls", "NativeCalls", "Neo"];
70
71pub fn builtin_intrinsic_surface() -> Vec<(&'static str, &'static [&'static str])> {
84 BUILTIN_LIBRARY_BASES
85 .iter()
86 .map(|base| {
87 (
88 *base,
89 builtin_library_supported_members(base)
90 .expect("every builtin library base has a member whitelist"),
91 )
92 })
93 .collect()
94}
95
96fn builtin_library_supported_members(base: &str) -> Option<&'static [&'static str]> {
97 match base {
98 "Runtime" => Some(&[
99 "notify",
100 "notifyIndexed",
101 "checkWitness",
102 "requireWitness",
103 "checkAnyWitness",
104 "checkAllWitnesses",
105 "checkMultiSigWitness",
106 "gasLeft",
107 "burnGas",
108 "log",
109 "getTime",
110 "getTrigger",
111 "getInvocationCounter",
112 "getCurrentSigners",
113 "getCallFlags",
114 "getScriptContainer",
115 "loadScript",
116 "initializeServices",
117 "getNetwork",
118 "getPlatform",
119 "getAddressVersion",
120 "getRandom",
121 "getExecutingScriptHash",
122 "getCallingScriptHash",
123 "getEntryScriptHash",
124 ]),
125 "abi" => Some(&[
126 "encode",
127 "encodePacked",
128 "encodeCall",
129 "encodeWithSignature",
130 "encodeWithSelector",
131 "decode",
132 ]),
133 "Storage" => Some(&[
142 "find",
143 "put",
144 "get",
145 "remove",
146 "asReadOnly",
147 "initializeContext",
148 "getContext",
149 "getReadOnlyContext",
150 "putContractMetadata",
151 ]),
152 "Syscalls" => Some(&[
153 "contractCall",
154 "contractCallWithFlags",
155 "getCallFlags",
156 "contractCreate",
157 "contractUpdate",
158 "contractDestroy",
159 "createStandardAccount",
160 "createMultisigAccount",
161 "notify",
162 "getCurrentIndex",
163 "getCurrentHash",
164 "getBlock",
165 "getTransaction",
166 "getTransactionHeight",
167 "getTransactionFromBlock",
168 "getTransactionSigners",
169 "getTransactionVMState",
170 "getExecutingScriptHash",
171 "getCallingScriptHash",
172 "getEntryScriptHash",
173 "getScriptContainer",
174 "loadScript",
175 "getStorageContext",
176 "getReadOnlyStorageContext",
177 "storageAsReadOnly",
178 "storageGet",
179 "storagePut",
180 "storageDelete",
181 "storageFind",
182 "checkWitness",
183 "getTime",
184 "gasLeft",
185 "getPlatform",
186 "getTrigger",
187 "getNotifications",
188 "log",
189 "getCurrentSigners",
190 "checkSig",
191 "checkMultisig",
192 "sha256",
193 "ripemd160",
194 "verifyWithECDsa",
195 "murmur32",
196 "keccak256",
197 "recoverSecp256K1",
198 "verifyWithEd25519",
199 "bls12381Serialize",
200 "bls12381Deserialize",
201 "bls12381Equal",
202 "bls12381Add",
203 "bls12381Mul",
204 "bls12381Pairing",
205 "bls12381G1Add",
212 "bls12381G1Mul",
213 "bls12381G1Neg",
214 "bls12381G2Add",
215 "bls12381G2Mul",
216 "bls12381G2Neg",
217 "neoKeccak256",
221 "serialize",
222 "deserialize",
223 "itoa",
224 "atoi",
225 "jsonSerialize",
226 "jsonDeserialize",
227 "base64Encode",
228 "base64Decode",
229 "base64UrlEncode",
230 "base64UrlDecode",
231 "base58Encode",
232 "base58Decode",
233 "base58CheckEncode",
234 "base58CheckDecode",
235 "hexEncode",
236 "hexDecode",
237 "memoryCompare",
238 "memorySearch",
239 "stringSplit",
240 "strLen",
241 "iteratorNext",
242 "iteratorValue",
243 "getCurrentRandom",
244 "getNetwork",
245 "getAddressVersion",
246 "burnGas",
247 "getInvocationCounter",
248 "getFeePerByte",
249 "getExecFeeFactor",
250 "getExecPicoFeeFactor",
251 "getStoragePrice",
252 "getMillisecondsPerBlock",
253 "getMaxValidUntilBlockIncrement",
254 "getMaxTraceableBlocks",
255 "getAttributeFee",
256 "isBlocked",
257 "oracleRequest",
258 "getOraclePrice",
259 "getDesignatedByRole",
260 "scriptHashToAddress",
261 "addressToScriptHash",
262 "isValidAddress",
263 "getContractScript",
264 "contractExists",
265 ]),
266 "NativeCalls" => Some(&[
267 "neoTotalSupply",
268 "neoBalanceOf",
269 "neoTransfer",
270 "neoDecimals",
271 "neoSymbol",
272 "neoName",
273 "vote",
274 "getCandidates",
275 "registerCandidate",
276 "unregisterCandidate",
277 "getGasPerBlock",
278 "getRegisterPrice",
279 "setRegisterPrice",
280 "setGasPerBlock",
281 "getAccountState",
282 "unclaimedGas",
283 "getCandidateVote",
284 "getCommittee",
285 "getCommitteeAddress",
286 "isCommittee",
287 "getNextBlockValidators",
288 "getAllCandidates",
289 "isValidator",
290 "gasTotalSupply",
291 "gasBalanceOf",
292 "gasTransfer",
293 "gasDecimals",
294 "gasSymbol",
295 "gasName",
296 "deployContract",
297 "updateContract",
298 "destroyContract",
299 "getContract",
300 "listContracts",
301 "hasMethod",
302 "getMinimumDeploymentFee",
303 "setMinimumDeploymentFee",
304 "getContractById",
305 "isContract",
306 "getFeePerByte",
307 "setFeePerByte",
308 "getExecFeeFactor",
309 "getExecPicoFeeFactor",
310 "setExecFeeFactor",
311 "getStoragePrice",
312 "getMillisecondsPerBlock",
313 "setMillisecondsPerBlock",
314 "getMaxValidUntilBlockIncrement",
315 "setMaxValidUntilBlockIncrement",
316 "getMaxTraceableBlocks",
317 "setMaxTraceableBlocks",
318 "getAttributeFee",
319 "setAttributeFee",
320 "setStoragePrice",
321 "blockAccount",
322 "unblockAccount",
323 "isBlocked",
324 "getBlockedAccounts",
325 "recoverFund",
326 "setWhitelistFeeContract",
327 "removeWhitelistFeeContract",
328 "getWhitelistFeeContracts",
329 "requestOracleData",
330 "getOraclePrice",
331 "setOraclePrice",
332 "oracleFinish",
333 "oracleVerify",
334 "oracleRequest",
335 "designateAsRole",
336 "getDesignatedByRole",
337 "currentIndex",
338 "currentHash",
339 "getBlock",
340 "getBlockHash",
341 "getBlockByIndex",
342 "getBlockByHash",
343 "getTransaction",
344 "getTransactionHeight",
345 "getTransactionFromBlock",
346 "getTransactionSigners",
347 "getTransactionVMState",
348 "getBlockSystemFee",
349 "notaryVerify",
350 "notaryBalanceOf",
351 "notaryExpirationOf",
352 "notaryLockDepositUntil",
353 "notaryWithdraw",
354 "notaryGetMaxNotValidBeforeDelta",
355 "notarySetMaxNotValidBeforeDelta",
356 "notaryOnNEP17Payment",
357 "treasuryVerify",
358 "treasuryOnNEP17Payment",
359 "treasuryOnNEP11Payment",
360 "isNativeContract",
361 "getNativeContractName",
362 "getAllNativeContracts",
363 "estimateNativeCallGas",
364 "batchNativeCalls",
365 "getNetworkConfiguration",
366 "getNativeContractManifest",
367 "safeNativeCall",
368 "externalNativeCall",
369 ]),
370 "Neo" => Some(&[
371 "verifySignature",
372 "callContract",
373 "deployContract",
374 "getNeoBalance",
375 "getGasBalance",
376 "getGasPrice",
377 "getStoragePrice",
378 "getCommittee",
379 "getValidators",
380 "isCommittee",
381 "isValidator",
382 "getRandom",
383 "getBlockHeight",
384 "getCurrentBlock",
385 "getBlockByIndex",
386 "getBlockTime",
387 "getTransaction",
388 "getTransactionHeight",
389 "transactionExists",
390 "getNetworkMagic",
391 "verifyWithWitness",
392 "sha256Hash",
393 "ripemd160Hash",
394 "transferNeo",
400 "transferGas",
401 ]),
402 _ => None,
403 }
404}
405
406fn resolve_runtime_member(member: &str) -> Option<BuiltinCall> {
407 match member {
408 "notify" => Some(BuiltinCall::RuntimeNotify),
409 "checkWitness" => Some(BuiltinCall::RuntimeCheckWitness),
410 "gasLeft" => Some(BuiltinCall::Syscall("System.Runtime.GasLeft".to_string())),
411 "burnGas" => Some(BuiltinCall::Syscall("System.Runtime.BurnGas".to_string())),
412 "log" => Some(BuiltinCall::Syscall("System.Runtime.Log".to_string())),
413 "getTime" => Some(BuiltinCall::Syscall("System.Runtime.GetTime".to_string())),
414 "getTrigger" => Some(BuiltinCall::Syscall(
415 "System.Runtime.GetTrigger".to_string(),
416 )),
417 "getInvocationCounter" => Some(BuiltinCall::Syscall(
418 "System.Runtime.GetInvocationCounter".to_string(),
419 )),
420 "getCurrentSigners" => Some(BuiltinCall::Syscall(
421 "System.Runtime.CurrentSigners".to_string(),
422 )),
423 "getCallFlags" => Some(BuiltinCall::Syscall(
424 "System.Contract.GetCallFlags".to_string(),
425 )),
426 "getScriptContainer" => Some(BuiltinCall::Syscall(
427 "System.Runtime.GetScriptContainer".to_string(),
428 )),
429 "loadScript" => Some(BuiltinCall::Syscall(
430 "System.Runtime.LoadScript".to_string(),
431 )),
432 "getNetwork" => Some(BuiltinCall::Syscall(
433 "System.Runtime.GetNetwork".to_string(),
434 )),
435 "getPlatform" => Some(BuiltinCall::Syscall("System.Runtime.Platform".to_string())),
436 "getAddressVersion" => Some(BuiltinCall::Syscall(
437 "System.Runtime.GetAddressVersion".to_string(),
438 )),
439 "getRandom" => Some(BuiltinCall::Syscall("System.Runtime.GetRandom".to_string())),
440 "getExecutingScriptHash" => Some(BuiltinCall::Syscall(
441 "System.Runtime.GetExecutingScriptHash".to_string(),
442 )),
443 "getCallingScriptHash" => Some(BuiltinCall::Syscall(
444 "System.Runtime.GetCallingScriptHash".to_string(),
445 )),
446 "getEntryScriptHash" => Some(BuiltinCall::Syscall(
447 "System.Runtime.GetEntryScriptHash".to_string(),
448 )),
449 _ => None,
450 }
451}
452
453fn resolve_abi_member(member: &str) -> Option<BuiltinCall> {
454 match member {
455 "encode" => Some(BuiltinCall::AbiEncode),
456 "encodePacked" => Some(BuiltinCall::AbiEncodePacked),
457 "encodeCall" => Some(BuiltinCall::AbiEncodeCall),
458 "encodeWithSignature" => Some(BuiltinCall::AbiEncodeWithSignature),
459 "encodeWithSelector" => Some(BuiltinCall::AbiEncodeWithSignature),
460 "decode" => Some(BuiltinCall::AbiDecode),
461 _ => None,
462 }
463}
464
465fn resolve_storage_member(member: &str) -> Option<BuiltinCall> {
466 match member {
475 "find" => Some(BuiltinCall::StorageFind),
476 "put" => Some(BuiltinCall::StoragePut),
477 "get" => Some(BuiltinCall::StorageGet),
478 "remove" => Some(BuiltinCall::StorageDelete),
479 "initializeContext" => Some(BuiltinCall::Syscall(
480 "System.Storage.GetContext".to_string(),
481 )),
482 "getContext" => Some(BuiltinCall::Syscall(
483 "System.Storage.GetContext".to_string(),
484 )),
485 "getReadOnlyContext" => Some(BuiltinCall::Syscall(
486 "System.Storage.GetReadOnlyContext".to_string(),
487 )),
488 "asReadOnly" => Some(BuiltinCall::Syscall(
489 "System.Storage.AsReadOnly".to_string(),
490 )),
491 _ => None,
492 }
493}
494
495fn resolve_neo_member(member: &str) -> Option<BuiltinCall> {
496 match member {
497 "verifySignature" => Some(BuiltinCall::VerifySignature),
498 "callContract" => Some(BuiltinCall::ContractCall),
499 "deployContract" => Some(BuiltinCall::DeployContract),
500 "getNeoBalance" => Some(BuiltinCall::NativeCall {
501 contract: NativeContract::Neo,
502 method: "balanceOf".to_string(),
503 }),
504 "getGasBalance" => Some(BuiltinCall::NativeCall {
505 contract: NativeContract::Gas,
506 method: "balanceOf".to_string(),
507 }),
508 "getGasPrice" => Some(BuiltinCall::NativeCall {
509 contract: NativeContract::Policy,
510 method: "getFeePerByte".to_string(),
511 }),
512 "getStoragePrice" => Some(BuiltinCall::NativeCall {
513 contract: NativeContract::Policy,
514 method: "getStoragePrice".to_string(),
515 }),
516 "getCommittee" => Some(BuiltinCall::NativeCall {
517 contract: NativeContract::Neo,
518 method: "getCommittee".to_string(),
519 }),
520 "getValidators" => Some(BuiltinCall::NativeCall {
521 contract: NativeContract::Neo,
522 method: "getNextBlockValidators".to_string(),
523 }),
524 "isCommittee" => Some(BuiltinCall::NativeCall {
525 contract: NativeContract::Neo,
526 method: "getCommittee".to_string(),
527 }),
528 "isValidator" => Some(BuiltinCall::NativeCall {
529 contract: NativeContract::Neo,
530 method: "getNextBlockValidators".to_string(),
531 }),
532 "getRandom" => Some(BuiltinCall::Syscall("System.Runtime.GetRandom".to_string())),
533 "getBlockHeight" => Some(BuiltinCall::NativeCall {
534 contract: NativeContract::Ledger,
535 method: "currentIndex".to_string(),
536 }),
537 "getCurrentBlock" => Some(BuiltinCall::NativeCall {
538 contract: NativeContract::Ledger,
539 method: "currentIndex".to_string(),
540 }),
541 "transactionExists" => Some(BuiltinCall::NativeCall {
542 contract: NativeContract::Ledger,
543 method: "getTransaction".to_string(),
544 }),
545 "getNetworkMagic" => Some(BuiltinCall::Syscall(
546 "System.Runtime.GetNetwork".to_string(),
547 )),
548 "getBlockByIndex" => Some(BuiltinCall::NativeCall {
549 contract: NativeContract::Ledger,
550 method: "getBlock".to_string(),
551 }),
552 "getBlockTime" => Some(BuiltinCall::Syscall("System.Runtime.GetTime".to_string())),
553 "getTransaction" => Some(BuiltinCall::NativeCall {
554 contract: NativeContract::Ledger,
555 method: "getTransaction".to_string(),
556 }),
557 "getTransactionHeight" => Some(BuiltinCall::NativeCall {
558 contract: NativeContract::Ledger,
559 method: "getTransactionHeight".to_string(),
560 }),
561 "verifyWithWitness" => Some(BuiltinCall::Syscall(
562 "System.Runtime.CheckWitness".to_string(),
563 )),
564 "sha256Hash" => Some(BuiltinCall::NativeCall {
565 contract: NativeContract::CryptoLib,
566 method: "sha256".to_string(),
567 }),
568 "ripemd160Hash" => Some(BuiltinCall::NativeCall {
569 contract: NativeContract::CryptoLib,
570 method: "ripemd160".to_string(),
571 }),
572 _ => None,
573 }
574}
575
576fn resolve_stdlib_member(member: &str) -> Option<BuiltinCall> {
582 match member {
583 "serialize" | "deserialize" | "jsonSerialize" | "jsonDeserialize" | "itoa" | "atoi"
584 | "base64Encode" | "base64Decode" | "base64UrlEncode" | "base64UrlDecode"
585 | "base58Encode" | "base58Decode" | "base58CheckEncode" | "base58CheckDecode"
586 | "hexEncode" | "hexDecode" | "memoryCompare" | "memorySearch" | "stringSplit"
587 | "strLen" => Some(BuiltinCall::NativeCall {
588 contract: NativeContract::StdLib,
589 method: member.to_string(),
590 }),
591 _ => None,
592 }
593}
594
595fn resolve_cryptolib_member(member: &str) -> Option<BuiltinCall> {
599 match member {
600 "sha256" | "ripemd160" | "verifyWithECDsa" | "murmur32" | "keccak256"
601 | "recoverSecp256K1" | "verifyWithEd25519" | "bls12381Serialize"
602 | "bls12381Deserialize" | "bls12381Equal" | "bls12381Add" | "bls12381Mul"
603 | "bls12381Pairing" | "bls12381G1Add" | "bls12381G1Mul" | "bls12381G2Add"
604 | "bls12381G2Mul" | "bls12381G1Neg" | "bls12381G2Neg" => {
605 Some(BuiltinCall::NativeCall {
606 contract: NativeContract::CryptoLib,
607 method: member.to_string(),
608 })
609 }
610 _ => None,
611 }
612}
613
614#[cfg(test)]
623mod devpack_intrinsic_surface_tests {
624 use super::*;
625 use std::path::PathBuf;
626
627 fn special_case_lowerings(base: &str) -> &'static [&'static str] {
639 match base {
640 "Runtime" => &[
641 "initializeServices",
642 "notifyIndexed",
643 "notify",
644 "requireWitness",
645 "checkAnyWitness",
646 "checkAllWitnesses",
647 "checkMultiSigWitness",
648 ],
649 "Storage" => &["putContractMetadata"],
650 "Neo" => &[
651 "isCommittee",
652 "getCommittee",
653 "getValidators",
654 "isValidator",
655 "transferGas",
656 "transferNeo",
657 ],
658 _ => &[],
659 }
660 }
661
662 fn has_lowering(base: &str, member: &str) -> bool {
663 let resolved = match base {
664 "Runtime" => resolve_runtime_member(member).is_some(),
665 "Storage" => resolve_storage_member(member).is_some(),
666 "Neo" => resolve_neo_member(member).is_some(),
667 other => panic!("unexpected library base '{other}'"),
668 };
669 resolved || special_case_lowerings(base).contains(&member)
670 }
671
672 fn devpack_library_path(base: &str) -> PathBuf {
673 PathBuf::from(env!("CARGO_MANIFEST_DIR"))
674 .join("devpack")
675 .join("libraries")
676 .join(format!("{base}.sol"))
677 }
678
679 fn declared_public_functions(source: &str) -> Vec<String> {
683 let mut names = Vec::new();
684 for line in source.lines() {
685 let trimmed = line.trim_start();
686 let Some(rest) = trimmed.strip_prefix("function ") else {
687 continue;
688 };
689 let Some(name) = rest.split('(').next() else {
690 continue;
691 };
692 let name = name.trim();
693 if name.is_empty() || name.starts_with('_') {
694 continue;
695 }
696 if trimmed.contains(" private ") || trimmed.ends_with(" private") {
699 continue;
700 }
701 names.push(name.to_string());
702 }
703 names
704 }
705
706 #[test]
707 fn every_declared_devpack_library_function_has_an_intrinsic_lowering() {
708 for base in ["Runtime", "Storage", "Neo"] {
709 let path = devpack_library_path(base);
710 let source = std::fs::read_to_string(&path)
711 .unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()));
712 let declared = declared_public_functions(&source);
713 assert!(
714 !declared.is_empty(),
715 "no function declarations found in {} — extraction regressed?",
716 path.display()
717 );
718
719 let missing: Vec<&String> = declared
720 .iter()
721 .filter(|name| !has_lowering(base, name))
722 .collect();
723 assert!(
724 missing.is_empty(),
725 "devpack/libraries/{base}.sol declares functions with no compiler \
726 lowering (calls would hard-fail; prune them or add a lowering): {missing:?}"
727 );
728 }
729 }
730
731 #[test]
732 fn every_declared_devpack_library_function_is_whitelisted() {
733 for base in ["Runtime", "Storage", "Neo"] {
737 let path = devpack_library_path(base);
738 let source = std::fs::read_to_string(&path)
739 .unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()));
740 let whitelist =
741 builtin_library_supported_members(base).expect("builtin library whitelist");
742 let missing: Vec<String> = declared_public_functions(&source)
743 .into_iter()
744 .filter(|name| !whitelist.contains(&name.as_str()))
745 .collect();
746 assert!(
747 missing.is_empty(),
748 "devpack/libraries/{base}.sol declares functions missing from \
749 builtin_library_supported_members: {missing:?}"
750 );
751 }
752 }
753
754 #[test]
755 fn every_whitelisted_member_has_an_intrinsic_lowering() {
756 for base in ["Runtime", "Storage", "Neo"] {
760 let whitelist =
761 builtin_library_supported_members(base).expect("builtin library whitelist");
762 let missing: Vec<&&str> = whitelist
763 .iter()
764 .filter(|member| !has_lowering(base, member))
765 .collect();
766 assert!(
767 missing.is_empty(),
768 "builtin_library_supported_members(\"{base}\") lists members \
769 with no compiler lowering: {missing:?}"
770 );
771 }
772 }
773
774 #[test]
775 fn fictional_local_storage_syscalls_are_not_resolvable() {
776 for member in ["putLocal", "getLocal", "removeLocal", "findLocal"] {
783 assert!(
784 resolve_storage_member(member).is_none(),
785 "Storage.{member} must not resolve to an intrinsic"
786 );
787 assert!(
788 !builtin_library_supported_members("Storage")
789 .expect("Storage whitelist")
790 .contains(&member),
791 "Storage.{member} must not be whitelisted"
792 );
793 }
794 for member in [
795 "storageGetLocal",
796 "storagePutLocal",
797 "storageDeleteLocal",
798 "storageFindLocal",
799 ] {
800 assert!(
801 resolve_syscalls_member(member).is_none(),
802 "Syscalls.{member} must not resolve to an intrinsic"
803 );
804 assert!(
805 !builtin_library_supported_members("Syscalls")
806 .expect("Syscalls whitelist")
807 .contains(&member),
808 "Syscalls.{member} must not be whitelisted"
809 );
810 }
811 }
812
813 #[test]
814 fn miscompiling_storage_helpers_are_not_resolvable() {
815 for member in [
821 "batchPut",
822 "batchGet",
823 "batchDelete",
824 "count",
825 "countLocal",
826 "findValues",
827 "findLocalValues",
828 "findKeys",
829 "findLocalKeys",
830 "clearPrefix",
831 "exists",
832 "isValidKey",
833 "getUsage",
834 ] {
835 assert!(
836 resolve_storage_member(member).is_none(),
837 "Storage.{member} must not resolve to an intrinsic"
838 );
839 assert!(
840 !builtin_library_supported_members("Storage")
841 .expect("Storage whitelist")
842 .contains(&member),
843 "Storage.{member} must not be whitelisted"
844 );
845 }
846 }
847
848 #[test]
849 fn no_resolver_emits_syscalls_outside_the_neo_n3_interop_table() {
850 const CANONICAL: &[&str] = &[
856 "System.Contract.Call",
857 "System.Contract.CallNative",
858 "System.Contract.CreateMultisigAccount",
859 "System.Contract.CreateStandardAccount",
860 "System.Contract.GetCallFlags",
861 "System.Contract.NativeOnPersist",
862 "System.Contract.NativePostPersist",
863 "System.Crypto.CheckMultisig",
864 "System.Crypto.CheckSig",
865 "System.Iterator.Next",
866 "System.Iterator.Value",
867 "System.Runtime.BurnGas",
868 "System.Runtime.CheckWitness",
869 "System.Runtime.CurrentSigners",
870 "System.Runtime.GasLeft",
871 "System.Runtime.GetAddressVersion",
872 "System.Runtime.GetCallingScriptHash",
873 "System.Runtime.GetEntryScriptHash",
874 "System.Runtime.GetExecutingScriptHash",
875 "System.Runtime.GetInvocationCounter",
876 "System.Runtime.GetNetwork",
877 "System.Runtime.GetNotifications",
878 "System.Runtime.GetRandom",
879 "System.Runtime.GetScriptContainer",
880 "System.Runtime.GetTime",
881 "System.Runtime.GetTrigger",
882 "System.Runtime.LoadScript",
883 "System.Runtime.Log",
884 "System.Runtime.Notify",
885 "System.Runtime.Platform",
886 "System.Storage.AsReadOnly",
887 "System.Storage.Delete",
888 "System.Storage.Find",
889 "System.Storage.Get",
890 "System.Storage.GetContext",
891 "System.Storage.GetReadOnlyContext",
892 "System.Storage.Put",
893 ];
894
895 let probe = |label: &str, builtin: Option<BuiltinCall>| {
896 if let Some(BuiltinCall::Syscall(name)) = builtin {
897 assert!(
898 CANONICAL.contains(&name.as_str()),
899 "{label} lowers to syscall '{name}' which is not in the \
900 Neo N3 interop table"
901 );
902 }
903 };
904
905 for base in ["Runtime", "Storage", "Syscalls", "Neo"] {
906 let members = builtin_library_supported_members(base).expect("whitelist");
907 for member in members {
908 let builtin = match base {
909 "Runtime" => resolve_runtime_member(member),
910 "Storage" => resolve_storage_member(member),
911 "Syscalls" => resolve_syscalls_member(member),
912 "Neo" => resolve_neo_member(member),
913 _ => unreachable!(),
914 };
915 probe(&format!("{base}.{member}"), builtin);
916 }
917 }
918 }
919}