evm.rs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // SPDX-License-Identifier: Apache-2.0
  2. use rayon::prelude::*;
  3. use solang::{file_resolver::FileResolver, parse_and_resolve, sema::ast, Target};
  4. use std::{ffi::OsStr, fs, path::Path};
  5. use walkdir::WalkDir;
  6. fn test_solidity(src: &str) -> ast::Namespace {
  7. let mut cache = FileResolver::default();
  8. cache.set_file_contents("test.sol", src.to_string());
  9. let ns = parse_and_resolve(OsStr::new("test.sol"), &mut cache, Target::EVM);
  10. ns.print_diagnostics_in_plain(&cache, false);
  11. ns
  12. }
  13. #[test]
  14. fn address() {
  15. let ns = test_solidity(
  16. "
  17. contract address_tester {
  18. function encode_const() public returns (address) {
  19. return 0x52908400098527886E0F7030069857D2E4169EE7;
  20. }
  21. function test_arg(address foo) public {
  22. assert(foo == 0x27b1fdb04752bbc536007a920d24acb045561c26);
  23. // this literal is a number
  24. int x = 0x27b1fdb047_52bbc536007a920d24acb045561C26;
  25. assert(int(foo) == x);
  26. }
  27. function allones() public returns (address) {
  28. return address(1);
  29. }
  30. }",
  31. );
  32. assert!(!ns.diagnostics.any_errors());
  33. }
  34. #[test]
  35. fn try_catch() {
  36. let ns = test_solidity(
  37. r#"
  38. contract b {
  39. int32 x;
  40. constructor(int32 a) public {
  41. x = a;
  42. }
  43. function get_x(int32 t) public returns (int32) {
  44. if (t == 0) {
  45. revert("cannot be zero");
  46. }
  47. return x * t;
  48. }
  49. }
  50. contract c {
  51. b x;
  52. constructor() public {
  53. x = new b(102);
  54. }
  55. function test() public returns (int32) {
  56. int32 state = 0;
  57. try x.get_x(0) returns (int32 l) {
  58. state = 1;
  59. } catch Error(string err) {
  60. if (err == "cannot be zero") {
  61. state = 2;
  62. } else {
  63. state = 3;
  64. }
  65. } catch (bytes ) {
  66. state = 4;
  67. }
  68. return state;
  69. }
  70. }"#,
  71. );
  72. assert!(!ns.diagnostics.any_errors());
  73. }
  74. #[test]
  75. fn selfdestruct() {
  76. let ns = test_solidity(
  77. r##"
  78. contract other {
  79. function goaway(address payable recipient) public returns (bool) {
  80. selfdestruct(recipient);
  81. }
  82. }
  83. contract c {
  84. other o;
  85. function step1() public {
  86. o = new other{value: 511}();
  87. }
  88. function step2() public {
  89. bool foo = o.goaway(payable(address(this)));
  90. }
  91. }"##,
  92. );
  93. assert!(!ns.diagnostics.any_errors());
  94. }
  95. #[test]
  96. fn eth_builtins() {
  97. let ns = test_solidity(
  98. r#"
  99. contract testing {
  100. function test_address() public view returns (uint256 ret) {
  101. assembly {
  102. let a := address()
  103. ret := a
  104. }
  105. }
  106. function test_balance() public view returns (uint256 ret) {
  107. assembly {
  108. let a := address()
  109. ret := balance(a)
  110. }
  111. }
  112. function test_selfbalance() public view returns (uint256 ret) {
  113. assembly {
  114. let a := selfbalance()
  115. ret := a
  116. }
  117. }
  118. function test_caller() public view returns (uint256 ret) {
  119. assembly {
  120. let a := caller()
  121. ret := a
  122. }
  123. }
  124. function test_callvalue() public view returns (uint256 ret) {
  125. assembly {
  126. let a := callvalue()
  127. ret := a
  128. }
  129. }
  130. function test_extcodesize() public view returns (uint256 ret) {
  131. assembly {
  132. let a := address()
  133. ret := extcodesize(a)
  134. }
  135. }
  136. }
  137. "#,
  138. );
  139. assert!(!ns.diagnostics.any_errors());
  140. }
  141. #[test]
  142. fn ethereum_solidity_tests() {
  143. let error_matcher =
  144. regex::Regex::new(r"// ----\r?\n(// Warning \d+: .*\n)*// \w+Error( \d+)?: (.*)").unwrap();
  145. let entries = WalkDir::new(
  146. Path::new(env!("CARGO_MANIFEST_DIR"))
  147. .join("testdata/solidity/test/libsolidity/semanticTests"),
  148. )
  149. .into_iter()
  150. .chain(WalkDir::new(
  151. Path::new(env!("CARGO_MANIFEST_DIR"))
  152. .join("testdata/solidity/test/libsolidity/syntaxTests"),
  153. ));
  154. let errors: usize = entries
  155. .par_bridge()
  156. .filter_map(|e| {
  157. let entry = e.unwrap();
  158. let file_name = entry.file_name().to_string_lossy();
  159. // FIXME: max_depth_reached_4.sol causes a stack overflow in resolve_expression.rs
  160. // FIXME: others listed explicitly cause panics and need fixing
  161. if !file_name.ends_with("max_depth_reached_4.sol")
  162. && !file_name.ends_with("invalid_utf8_sequence.sol")
  163. && file_name.ends_with(".sol")
  164. {
  165. Some(entry)
  166. } else {
  167. None
  168. }
  169. })
  170. .map(|entry| {
  171. let path = entry.path().parent().unwrap();
  172. let source = fs::read_to_string(entry.path()).unwrap();
  173. let expect_error = error_matcher
  174. .captures(&source)
  175. .map(|captures| captures.get(3).unwrap().as_str());
  176. let (mut cache, names) = set_file_contents(&source, entry.path());
  177. cache.add_import_path(path).unwrap();
  178. let errors: usize = names
  179. .iter()
  180. .map(|name| {
  181. let ns = parse_and_resolve(OsStr::new(&name), &mut cache, Target::EVM);
  182. if ns.diagnostics.any_errors() {
  183. if expect_error.is_none() {
  184. println!("file: {} name:{}", entry.path().display(), name);
  185. ns.print_diagnostics_in_plain(&cache, false);
  186. 1
  187. } else {
  188. 0
  189. }
  190. } else if let Some(error) = expect_error {
  191. println!("file: {} name:{}", entry.path().display(), name);
  192. println!("expecting error {error}");
  193. 1
  194. } else {
  195. 0
  196. }
  197. })
  198. .sum();
  199. errors
  200. })
  201. .sum();
  202. assert_eq!(errors, 1036);
  203. }
  204. fn set_file_contents(source: &str, path: &Path) -> (FileResolver, Vec<String>) {
  205. let mut cache = FileResolver::default();
  206. let mut name = path.to_string_lossy().to_string();
  207. let mut names = Vec::new();
  208. let mut contents = String::new();
  209. let source_delimiter = regex::Regex::new(r"==== Source: (.*) ====").unwrap();
  210. let external_source_delimiter = regex::Regex::new(r"==== ExternalSource: (.*) ====").unwrap();
  211. let equals = regex::Regex::new("([a-zA-Z0-9_]+)=(.*)").unwrap();
  212. for line in source.lines() {
  213. if let Some(cap) = source_delimiter.captures(line) {
  214. if !contents.is_empty() {
  215. cache.set_file_contents(&name, contents);
  216. names.push(name);
  217. }
  218. name = cap.get(1).unwrap().as_str().to_owned();
  219. if name == "////" {
  220. name = "test.sol".to_owned();
  221. }
  222. contents = String::new();
  223. } else if let Some(cap) = external_source_delimiter.captures(line) {
  224. let mut name = cap.get(1).unwrap().as_str().to_owned();
  225. if let Some(cap) = equals.captures(&name) {
  226. let mut ext = path.parent().unwrap().to_path_buf();
  227. ext.push(cap.get(2).unwrap().as_str());
  228. name = cap.get(1).unwrap().as_str().to_owned();
  229. let source = fs::read_to_string(ext).unwrap();
  230. cache.set_file_contents(&name, source);
  231. }
  232. // else rely on file resolver to import stuff
  233. } else {
  234. contents.push_str(line);
  235. contents.push('\n');
  236. }
  237. }
  238. if !contents.is_empty() {
  239. cache.set_file_contents(&name, contents);
  240. names.push(name);
  241. }
  242. (cache, names)
  243. }