errors.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::build_solidity;
  3. use parity_scale_codec::{Decode, Encode};
  4. use primitive_types::U256;
  5. use solang::codegen::{
  6. revert::{PanicCode, PanicCode::*, SolidityError},
  7. Expression,
  8. };
  9. #[derive(Encode, Decode)]
  10. struct PanicData {
  11. selector: [u8; 4],
  12. data: U256,
  13. }
  14. impl From<PanicCode> for PanicData {
  15. fn from(value: PanicCode) -> Self {
  16. Self {
  17. selector: SolidityError::Panic(value).selector().to_be_bytes(),
  18. data: U256::from(value as u8),
  19. }
  20. }
  21. }
  22. #[derive(Encode, Decode)]
  23. struct ErrorData {
  24. selector: [u8; 4],
  25. msg: String,
  26. }
  27. impl From<String> for ErrorData {
  28. fn from(msg: String) -> Self {
  29. Self {
  30. selector: SolidityError::String(Expression::Poison)
  31. .selector()
  32. .to_be_bytes(),
  33. msg,
  34. }
  35. }
  36. }
  37. #[test]
  38. fn constructor_buf_too_small() {
  39. let mut runtime = build_solidity(
  40. r#"contract RuntimeErrors {
  41. function write_bytes_failure(uint8 buf_size) public pure {
  42. bytes data = new bytes(10);
  43. bytes smol_buf = new bytes(buf_size);
  44. smol_buf.writeBytes(data, 0);
  45. }
  46. }"#,
  47. );
  48. runtime.function_expect_failure("write_bytes_failure", 9u8.encode());
  49. assert!(runtime
  50. .debug_buffer()
  51. .contains("runtime_error: data does not fit into buffer in test.sol"));
  52. assert_eq!(runtime.output(), PanicData::from(ArrayIndexOob).encode());
  53. }
  54. #[test]
  55. fn math_overflow() {
  56. let mut runtime = build_solidity(
  57. r#"contract RuntimeErrors {
  58. function math_overflow(int8 num) public pure returns (int8) {
  59. int8 ovf = num + 120;
  60. return ovf;
  61. }
  62. }"#,
  63. );
  64. runtime.function_expect_failure("math_overflow", 10u8.encode());
  65. assert!(runtime
  66. .debug_buffer()
  67. .contains("runtime_error: math overflow in test.sol"));
  68. assert_eq!(runtime.output(), PanicData::from(MathOverflow).encode());
  69. }
  70. #[test]
  71. fn require() {
  72. let mut runtime = build_solidity(
  73. r#"contract RuntimeErrors {
  74. function require_test(int8 num) public pure returns (int8) {
  75. require(num > 10, "sesa");
  76. return 0;
  77. }
  78. }"#,
  79. );
  80. runtime.function_expect_failure("require_test", 9u8.encode());
  81. assert!(runtime
  82. .debug_buffer()
  83. .contains("runtime_error: sesa require condition failed in test.sol"));
  84. assert_eq!(
  85. runtime.output(),
  86. ErrorData::from("sesa".to_string()).encode()
  87. );
  88. }
  89. #[test]
  90. fn require_without_message() {
  91. let mut runtime = build_solidity(
  92. r#"contract RuntimeErrors {
  93. function require_test(int8 num) public pure returns (int8) {
  94. require(num > 10);
  95. return 0;
  96. }
  97. }"#,
  98. );
  99. runtime.function_expect_failure("require_test", 9u8.encode());
  100. assert!(runtime
  101. .debug_buffer()
  102. .contains("runtime_error: require condition failed in test.sol"));
  103. assert!(runtime.output().is_empty());
  104. }
  105. #[test]
  106. fn assert() {
  107. let mut runtime = build_solidity(
  108. r#"contract RuntimeErrors {
  109. function assert_test(int8 num) public returns (int8) {
  110. assert(num > 10);
  111. return 0;
  112. }
  113. }"#,
  114. );
  115. runtime.function_expect_failure("assert_test", 9u8.encode());
  116. assert!(runtime
  117. .debug_buffer()
  118. .contains("runtime_error: assert failure in test.sol"));
  119. assert_eq!(runtime.output(), PanicData::from(Assertion).encode());
  120. }
  121. #[test]
  122. fn set_storage_bytes_oob() {
  123. let mut runtime = build_solidity(
  124. r#"contract RuntimeErrors {
  125. bytes public b = hex"0000_00fa";
  126. function set_storage_bytes() public returns (bytes) {
  127. bytes sesa = new bytes(1);
  128. b[5] = sesa[0];
  129. return sesa;
  130. }
  131. }"#,
  132. );
  133. runtime.constructor(0, vec![]);
  134. runtime.function_expect_failure("set_storage_bytes", Vec::new());
  135. assert!(runtime
  136. .debug_buffer()
  137. .contains("runtime_error: storage index out of bounds in test.sol"));
  138. assert_eq!(runtime.output(), PanicData::from(ArrayIndexOob).encode());
  139. }
  140. #[test]
  141. fn get_storage_bytes_oob() {
  142. let mut runtime = build_solidity(
  143. r#"contract RuntimeErrors {
  144. bytes public b = hex"0000_00fa";
  145. function get_storage_bytes() public returns (bytes) {
  146. bytes sesa = new bytes(1);
  147. sesa[0] = b[5];
  148. return sesa;
  149. }
  150. }"#,
  151. );
  152. runtime.constructor(0, vec![]);
  153. runtime.function_expect_failure("get_storage_bytes", Vec::new());
  154. assert!(runtime
  155. .debug_buffer()
  156. .contains("runtime_error: storage array index out of bounds in test.sol"));
  157. assert_eq!(runtime.output(), PanicData::from(ArrayIndexOob).encode());
  158. }
  159. #[test]
  160. fn transfer_fails() {
  161. let mut runtime = build_solidity(
  162. r#"contract RuntimeErrors {
  163. function transfer_abort() public {
  164. address a = address(0);
  165. payable(a).transfer(10);
  166. }
  167. }"#,
  168. );
  169. runtime.function_expect_failure("transfer_abort", Vec::new());
  170. assert!(runtime
  171. .debug_buffer()
  172. .contains("runtime_error: value transfer failure in test.sol"));
  173. assert!(runtime.output().is_empty());
  174. }
  175. #[test]
  176. fn empty_storage_array_pop() {
  177. let mut runtime = build_solidity(
  178. r#"contract RuntimeErrors {
  179. uint256[] public arr;
  180. function pop_empty_storage() public {
  181. arr.pop();
  182. }
  183. }"#,
  184. );
  185. runtime.constructor(0, vec![]);
  186. runtime.function_expect_failure("pop_empty_storage", Vec::new());
  187. assert!(runtime
  188. .debug_buffer()
  189. .contains("runtime_error: pop from empty storage array in test.sol"));
  190. assert_eq!(runtime.output(), PanicData::from(EmptyArrayPop).encode());
  191. }
  192. #[test]
  193. fn contract_instantiatoin_fail() {
  194. let mut runtime = build_solidity(
  195. r#"contract RuntimeErrors {
  196. child public c;
  197. child public c2;
  198. constructor() payable {}
  199. function create_child() public {
  200. c = new child{value: 900e15, salt: hex"02"}();
  201. c2 = new child{value: 900e15, salt: hex"02"}();
  202. uint128 x = address(this).balance;
  203. print("x = {}".format(x));
  204. }
  205. }
  206. contract child {
  207. function say_my_name() public pure returns (string memory) {
  208. print("say_my_name");
  209. return "child";
  210. }
  211. }"#,
  212. );
  213. runtime.set_transferred_value(3500);
  214. runtime.constructor(0, Vec::new());
  215. runtime.set_transferred_value(0);
  216. runtime.function_expect_failure("create_child", Vec::new());
  217. assert!(runtime
  218. .debug_buffer()
  219. .contains("runtime_error: contract creation failed in test.sol:6"));
  220. assert!(runtime.output().is_empty());
  221. }
  222. #[test]
  223. fn revert() {
  224. let mut runtime = build_solidity(
  225. r#"contract RuntimeErrors {
  226. function i_will_revert() public pure {
  227. revert();
  228. }
  229. function revert_dyn(string s) public pure {
  230. revert(s);
  231. }
  232. function revert_static() public pure {
  233. revert("hi");
  234. }
  235. }"#,
  236. );
  237. runtime.function_expect_failure("i_will_revert", Vec::new());
  238. assert!(runtime.debug_buffer().contains("runtime_error: revert"));
  239. assert!(runtime.output().is_empty());
  240. let msg = "hello \"\n\0world!".to_string();
  241. runtime.function_expect_failure("revert_dyn", msg.encode());
  242. assert!(runtime.debug_buffer().contains("revert encountered"));
  243. assert!(runtime.debug_buffer().contains(&msg));
  244. assert_eq!(runtime.output(), ErrorData::from(msg).encode());
  245. runtime.function_expect_failure("revert_static", Vec::new());
  246. assert!(runtime.debug_buffer().contains("runtime_error: hi revert"));
  247. assert_eq!(runtime.output(), ErrorData::from("hi".to_string()).encode());
  248. }
  249. #[test]
  250. fn int_too_large_for_bytes() {
  251. let mut runtime = build_solidity(
  252. r#"contract RuntimeErrors {
  253. function write_integer_failure(uint8 buf_size) public {
  254. bytes smol_buf = new bytes(buf_size);
  255. smol_buf.writeUint32LE(350, 20);
  256. }
  257. }"#,
  258. );
  259. runtime.function_expect_failure("write_integer_failure", 1u8.encode());
  260. assert!(runtime
  261. .debug_buffer()
  262. .contains("runtime_error: integer too large to write in buffer in test.sol"));
  263. assert_eq!(runtime.output(), PanicData::from(ArrayIndexOob).encode());
  264. }
  265. #[test]
  266. fn invalid_instruction() {
  267. let mut runtime = build_solidity(
  268. r#"contract RuntimeErrors {
  269. function invalid_instruction() public pure {
  270. assembly {
  271. invalid()
  272. }
  273. }
  274. }"#,
  275. );
  276. runtime.function_expect_failure("invalid_instruction", Vec::new());
  277. assert!(runtime
  278. .debug_buffer()
  279. .contains("runtime_error: reached invalid instruction in test.sol"));
  280. assert_eq!(runtime.output(), PanicData::from(Generic).encode());
  281. }
  282. #[test]
  283. fn array_index_oob() {
  284. let mut runtime = build_solidity(
  285. r#"contract RuntimeErrors {
  286. function out_of_bounds(uint8 input) public pure returns (uint256) {
  287. uint256[] a = new uint256[](input);
  288. return a[20];
  289. }
  290. }"#,
  291. );
  292. runtime.function_expect_failure("out_of_bounds", 19u8.encode());
  293. assert!(runtime
  294. .debug_buffer()
  295. .contains("runtime_error: array index out of bounds in test.sol"));
  296. assert_eq!(runtime.output(), PanicData::from(ArrayIndexOob).encode());
  297. }
  298. #[test]
  299. fn truncated_type_overflow() {
  300. let mut runtime = build_solidity(
  301. r#"contract RuntimeErrors {
  302. function trunc_failure(uint128 input) public returns (uint256) {
  303. uint256[] a = new uint256[](input);
  304. return a[0];
  305. }
  306. }"#,
  307. );
  308. runtime.function_expect_failure("trunc_failure", u128::MAX.encode());
  309. assert!(runtime
  310. .debug_buffer()
  311. .contains("runtime_error: truncated type overflows in test.sol"));
  312. assert_eq!(runtime.output(), PanicData::from(MathOverflow).encode());
  313. }
  314. #[test]
  315. fn byte_cast_fail() {
  316. let mut runtime = build_solidity(
  317. r#"contract RuntimeErrors {
  318. function byte_cast_failure(uint8 num) public pure returns (bytes) {
  319. bytes smol_buf = new bytes(num);
  320. bytes32 b32 = bytes32(smol_buf);
  321. return b32;
  322. }
  323. }"#,
  324. );
  325. runtime.function_expect_failure("byte_cast_failure", 33u8.encode());
  326. assert!(runtime
  327. .debug_buffer()
  328. .contains("runtime_error: bytes cast error in test.sol"));
  329. assert_eq!(
  330. runtime.output(),
  331. PanicData::from(PanicCode::Generic).encode()
  332. )
  333. }
  334. #[test]
  335. fn int_read_oob() {
  336. let mut runtime = build_solidity(
  337. r#"contract RuntimeErrors {
  338. function read_integer_failure(uint32 offset) public {
  339. bytes smol_buf = new bytes(1);
  340. smol_buf.readUint16LE(offset);
  341. }
  342. }"#,
  343. );
  344. runtime.function_expect_failure("read_integer_failure", 2u32.encode());
  345. assert!(runtime
  346. .debug_buffer()
  347. .contains("runtime_error: read integer out of bounds in test.sol"));
  348. assert_eq!(runtime.output(), PanicData::from(ArrayIndexOob).encode());
  349. }
  350. #[test]
  351. fn external_call() {
  352. let mut runtime = build_solidity(
  353. r#"contract RuntimeErrors {
  354. callee public cal;
  355. constructor() payable {}
  356. function call_ext() public {
  357. cal = new callee();
  358. cal.callee_func{gas: 1e15}();
  359. }
  360. }
  361. contract callee {
  362. function callee_func() public {
  363. revert();
  364. }
  365. }"#,
  366. );
  367. runtime.set_transferred_value(3500);
  368. runtime.constructor(0, vec![]);
  369. runtime.function_expect_failure("call_ext", Vec::new());
  370. assert!(runtime
  371. .debug_buffer()
  372. .contains("runtime_error: external call failed in test.sol"));
  373. assert!(runtime.output().is_empty());
  374. }
  375. #[test]
  376. fn non_payable_function_with_value() {
  377. let mut runtime =
  378. build_solidity(r#"contract RuntimeErrors { function dont_pay_me() public {} }"#);
  379. runtime.set_transferred_value(1);
  380. runtime.function_expect_failure("dont_pay_me", Vec::new());
  381. assert!(runtime
  382. .debug_buffer()
  383. .contains("runtime_error: non payable function dont_pay_me received value"));
  384. assert!(runtime.output().is_empty());
  385. }
  386. #[test]
  387. fn multiplication_overflow_big_u256() {
  388. let mut runtime = build_solidity(
  389. r#"contract RuntimeErrors {
  390. function pow(uint256 bar) public pure returns(uint256) {
  391. return bar ** 2;
  392. }
  393. function mul(uint256 bar) public pure returns(uint256) {
  394. return bar * 2;
  395. }
  396. }"#,
  397. );
  398. let expected_debug_output = "runtime_error: multiplication overflow";
  399. let expected_output = PanicData::from(MathOverflow).encode();
  400. runtime.function_expect_failure("pow", U256::MAX.encode());
  401. assert!(runtime.debug_buffer().contains(expected_debug_output));
  402. assert_eq!(runtime.output(), expected_output);
  403. runtime.function_expect_failure("mul", U256::MAX.encode());
  404. assert!(runtime.debug_buffer().contains(expected_debug_output));
  405. assert_eq!(runtime.output(), expected_output)
  406. }
  407. #[test]
  408. fn multiplication_overflow_u8() {
  409. let mut runtime = build_solidity(
  410. r#"contract RuntimeErrors {
  411. function pow(uint8 bar) public pure returns(uint8) {
  412. return bar ** 2;
  413. }
  414. function mul(uint8 bar) public pure returns(uint8) {
  415. return bar * 2;
  416. }
  417. }"#,
  418. );
  419. let expected_debug_output = "runtime_error: math overflow";
  420. let expected_output = PanicData::from(MathOverflow).encode();
  421. runtime.function_expect_failure("pow", u8::MAX.encode());
  422. assert!(runtime.debug_buffer().contains(expected_debug_output));
  423. assert_eq!(runtime.output(), expected_output);
  424. runtime.function_expect_failure("mul", u8::MAX.encode());
  425. assert!(runtime.debug_buffer().contains(expected_debug_output));
  426. assert_eq!(runtime.output(), expected_output)
  427. }
  428. #[test]
  429. fn empty_array_pop() {
  430. let mut runtime = build_solidity(
  431. r#"contract RuntimeErrors {
  432. function pop_empty_array() public pure returns(uint256[] arr) {
  433. arr.pop();
  434. }
  435. }"#,
  436. );
  437. runtime.function_expect_failure("pop_empty_array", vec![]);
  438. assert!(runtime.debug_buffer().contains("pop from empty array"));
  439. assert_eq!(runtime.output(), PanicData::from(EmptyArrayPop).encode());
  440. }
  441. #[test]
  442. fn uint256_div_by_zero() {
  443. let mut runtime = build_solidity(
  444. r#"contract RuntimeErrors {
  445. function div_by_zero(uint256 div) public pure returns(uint256 ret) {
  446. ret = ret / div;
  447. }
  448. function mod_zero(uint256 div) public pure returns(uint256 ret) {
  449. ret = ret % div;
  450. }
  451. }"#,
  452. );
  453. runtime.function_expect_failure("div_by_zero", U256::zero().encode());
  454. assert!(runtime.debug_buffer().contains("division by zero"));
  455. assert_eq!(runtime.output(), PanicData::from(DivisionByZero).encode());
  456. runtime.function_expect_failure("mod_zero", U256::zero().encode());
  457. assert!(runtime.debug_buffer().contains("division by zero"));
  458. assert_eq!(runtime.output(), PanicData::from(DivisionByZero).encode());
  459. }
  460. #[test]
  461. fn int256_div_by_zero() {
  462. let mut runtime = build_solidity(
  463. r#"contract RuntimeErrors {
  464. function div_by_zero(int256 div) public pure returns(int256 ret) {
  465. ret = ret / div;
  466. }
  467. function mod_zero(int256 div) public pure returns(int256 ret) {
  468. ret = ret % div;
  469. }
  470. }"#,
  471. );
  472. runtime.function_expect_failure("div_by_zero", U256::zero().encode());
  473. assert!(runtime.debug_buffer().contains("division by zero"));
  474. assert_eq!(runtime.output(), PanicData::from(DivisionByZero).encode());
  475. runtime.function_expect_failure("mod_zero", U256::zero().encode());
  476. assert!(runtime.debug_buffer().contains("division by zero"));
  477. assert_eq!(runtime.output(), PanicData::from(DivisionByZero).encode());
  478. }
  479. #[test]
  480. fn internal_dyn_call_on_nil() {
  481. let mut runtime = build_solidity(
  482. r#"contract RuntimeErrors {
  483. function() internal x;
  484. function f() public returns (uint r) {
  485. x();
  486. return 2;
  487. }
  488. }"#,
  489. );
  490. runtime.function_expect_failure("f", vec![]);
  491. assert!(runtime
  492. .debug_buffer()
  493. .contains("internal function uninitialized"));
  494. assert_eq!(
  495. runtime.output(),
  496. PanicData::from(InternalFunctionUninitialized).encode()
  497. );
  498. }