runtime_errors.rs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::{build_solidity, BorshToken};
  3. use num_bigint::BigInt;
  4. #[test]
  5. fn runtime_errors() {
  6. let mut vm = build_solidity(
  7. r#"
  8. contract RuntimeErrors {
  9. bytes b = hex"0000_00fa";
  10. uint256[] arr;
  11. child public c;
  12. child public c2;
  13. constructor() {}
  14. function print_test(int8 num) public returns (int8) {
  15. print("Hello world!");
  16. require(num > 10, "sesa");
  17. assert(num > 10);
  18. int8 ovf = num + 120;
  19. print("x = {}".format(ovf));
  20. return ovf;
  21. }
  22. function math_overflow(int8 num) public returns (int8) {
  23. int8 ovf = num + 120;
  24. print("x = {}".format(ovf));
  25. return ovf;
  26. }
  27. function require_test(int256 num) public returns (int8) {
  28. require(num > 10, "sesa");
  29. return 0;
  30. }
  31. // assert failure
  32. function assert_test(int256 num) public returns (int8) {
  33. assert(num > 10);
  34. return 0;
  35. }
  36. // storage index out of bounds
  37. function set_storage_bytes() public returns (bytes) {
  38. bytes sesa = new bytes(1);
  39. b[5] = sesa[0];
  40. return sesa;
  41. }
  42. // storage array index out of bounds
  43. function get_storage_bytes() public returns (bytes) {
  44. bytes sesa = new bytes(1);
  45. sesa[0] = b[5];
  46. return sesa;
  47. }
  48. // pop from empty storage array
  49. function pop_empty_storage() public {
  50. arr.pop();
  51. }
  52. function i_will_revert() public {
  53. revert();
  54. }
  55. function write_integer_failure(uint256 buf_size) public {
  56. bytes smol_buf = new bytes(buf_size);
  57. smol_buf.writeUint32LE(350, 20);
  58. }
  59. function write_bytes_failure(uint256 buf_size) public {
  60. bytes data = new bytes(10);
  61. bytes smol_buf = new bytes(buf_size);
  62. smol_buf.writeBytes(data, 0);
  63. }
  64. function read_integer_failure(uint32 offset) public {
  65. bytes smol_buf = new bytes(1);
  66. smol_buf.readUint16LE(offset);
  67. }
  68. // truncated type overflows
  69. function trunc_failure(uint256 input) public returns (uint256[]) {
  70. uint256[] a = new uint256[](input);
  71. return a;
  72. }
  73. function out_of_bounds(uint256 input) public returns (uint256) {
  74. uint256[] a = new uint256[](input);
  75. return a[20];
  76. }
  77. function invalid_instruction() public {
  78. assembly {
  79. invalid()
  80. }
  81. }
  82. function byte_cast_failure(uint256 num) public returns (bytes) {
  83. bytes smol_buf = new bytes(num);
  84. //bytes32 b32 = new bytes(num);
  85. bytes32 b32 = bytes32(smol_buf);
  86. return b32;
  87. }
  88. function revert_with_message() public pure {
  89. revert("I reverted!");
  90. }
  91. }
  92. @program_id("Crea1hXZv5Snuvs38GW2SJ1vJQ2Z5uBavUnwPwpiaDiQ")
  93. contract child {
  94. constructor() {}
  95. function say_my_name() public pure returns (string memory) {
  96. print("say_my_name");
  97. return "child";
  98. }
  99. }
  100. contract calle_contract {
  101. constructor() {}
  102. function calle_contract_func() public {
  103. revert();
  104. }
  105. }
  106. "#,
  107. );
  108. vm.set_program(0);
  109. let data_account = vm.initialize_data_account();
  110. vm.function("new")
  111. .accounts(vec![("dataAccount", data_account)])
  112. .call();
  113. let mut _res = vm
  114. .function("math_overflow")
  115. .arguments(&[BorshToken::Int {
  116. width: 8,
  117. value: BigInt::from(10u8),
  118. }])
  119. .accounts(vec![("dataAccount", data_account)])
  120. .must_fail();
  121. assert_eq!(
  122. vm.logs,
  123. "runtime_error: math overflow in test.sol:22:20-29,\n"
  124. );
  125. vm.logs.clear();
  126. _res = vm
  127. .function("require_test")
  128. .arguments(&[BorshToken::Int {
  129. width: 256,
  130. value: BigInt::from(9u8),
  131. }])
  132. .accounts(vec![("dataAccount", data_account)])
  133. .must_fail();
  134. assert_eq!(
  135. vm.logs,
  136. "runtime_error: sesa require condition failed in test.sol:28:27-33,\n"
  137. );
  138. vm.logs.clear();
  139. _res = vm
  140. .function("get_storage_bytes")
  141. .accounts(vec![("dataAccount", data_account)])
  142. .must_fail();
  143. assert_eq!(
  144. vm.logs,
  145. "runtime_error: storage array index out of bounds in test.sol:48:19-23,\n"
  146. );
  147. vm.logs.clear();
  148. _res = vm
  149. .function("set_storage_bytes")
  150. .accounts(vec![("dataAccount", data_account)])
  151. .must_fail();
  152. assert_eq!(
  153. vm.logs,
  154. "runtime_error: storage index out of bounds in test.sol:41:11-12,\n"
  155. );
  156. vm.logs.clear();
  157. _res = vm
  158. .function("read_integer_failure")
  159. .arguments(&[BorshToken::Uint {
  160. width: 32,
  161. value: BigInt::from(2u8),
  162. }])
  163. .accounts(vec![("dataAccount", data_account)])
  164. .must_fail();
  165. assert_eq!(
  166. vm.logs,
  167. "runtime_error: read integer out of bounds in test.sol:74:18-30,\n"
  168. );
  169. vm.logs.clear();
  170. _res = vm
  171. .function("trunc_failure")
  172. .arguments(&[BorshToken::Uint {
  173. width: 256,
  174. value: BigInt::from(u128::MAX),
  175. }])
  176. .accounts(vec![("dataAccount", data_account)])
  177. .must_fail();
  178. assert_eq!(
  179. vm.logs,
  180. "runtime_error: truncated type overflows in test.sol:79:37-42,\n"
  181. );
  182. vm.logs.clear();
  183. _res = vm
  184. .function("invalid_instruction")
  185. .accounts(vec![("dataAccount", data_account)])
  186. .must_fail();
  187. assert_eq!(
  188. vm.logs,
  189. "runtime_error: reached invalid instruction in test.sol:90:13-22,\n"
  190. );
  191. vm.logs.clear();
  192. _res = vm
  193. .function("pop_empty_storage")
  194. .accounts(vec![("dataAccount", data_account)])
  195. .must_fail();
  196. assert_eq!(
  197. vm.logs,
  198. "runtime_error: pop from empty storage array in test.sol:54:9-12,\n"
  199. );
  200. vm.logs.clear();
  201. _res = vm
  202. .function("write_bytes_failure")
  203. .arguments(&[BorshToken::Uint {
  204. width: 256,
  205. value: BigInt::from(9u8),
  206. }])
  207. .accounts(vec![("dataAccount", data_account)])
  208. .must_fail();
  209. assert_eq!(
  210. vm.logs,
  211. "runtime_error: data does not fit into buffer in test.sol:69:18-28,\n"
  212. );
  213. vm.logs.clear();
  214. _res = vm
  215. .function("assert_test")
  216. .arguments(&[BorshToken::Uint {
  217. width: 256,
  218. value: BigInt::from(9u8),
  219. }])
  220. .accounts(vec![("dataAccount", data_account)])
  221. .must_fail();
  222. println!("{}", vm.logs);
  223. assert_eq!(
  224. vm.logs,
  225. "runtime_error: assert failure in test.sol:34:16-24,\n"
  226. );
  227. vm.logs.clear();
  228. _res = vm
  229. .function("out_of_bounds")
  230. .arguments(&[BorshToken::Uint {
  231. width: 256,
  232. value: BigInt::from(19u8),
  233. }])
  234. .accounts(vec![("dataAccount", data_account)])
  235. .must_fail();
  236. assert_eq!(
  237. vm.logs,
  238. "runtime_error: array index out of bounds in test.sol:85:16-21,\n"
  239. );
  240. vm.logs.clear();
  241. _res = vm
  242. .function("write_integer_failure")
  243. .arguments(&[BorshToken::Uint {
  244. width: 256,
  245. value: BigInt::from(1u8),
  246. }])
  247. .accounts(vec![("dataAccount", data_account)])
  248. .must_fail();
  249. assert_eq!(
  250. vm.logs,
  251. "runtime_error: integer too large to write in buffer in test.sol:63:18-31,\n"
  252. );
  253. vm.logs.clear();
  254. _res = vm
  255. .function("byte_cast_failure")
  256. .arguments(&[BorshToken::Uint {
  257. width: 256,
  258. value: BigInt::from(33u8),
  259. }])
  260. .accounts(vec![("dataAccount", data_account)])
  261. .must_fail();
  262. assert_eq!(
  263. vm.logs,
  264. "runtime_error: bytes cast error in test.sol:98:23-40,\n"
  265. );
  266. vm.logs.clear();
  267. _res = vm
  268. .function("i_will_revert")
  269. .accounts(vec![("dataAccount", data_account)])
  270. .must_fail();
  271. assert_eq!(
  272. vm.logs,
  273. "runtime_error: revert encountered in test.sol:58:9-17,\n"
  274. );
  275. vm.logs.clear();
  276. _res = vm.function("revert_with_message").must_fail();
  277. assert_eq!(
  278. vm.logs,
  279. "runtime_error: I reverted! revert encountered in test.sol:103:9-30,\n"
  280. );
  281. assert!(vm.return_data.is_none());
  282. }