| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- // SPDX-License-Identifier: Apache-2.0
- use crate::{build_solidity, BorshToken};
- use num_bigint::BigInt;
- #[test]
- fn runtime_errors() {
- let mut vm = build_solidity(
- r#"
- contract RuntimeErrors {
- bytes b = hex"0000_00fa";
- uint256[] arr;
- child public c;
- child public c2;
- constructor() {}
- function print_test(int8 num) public returns (int8) {
- print("Hello world!");
- require(num > 10, "sesa");
- assert(num > 10);
- int8 ovf = num + 120;
- print("x = {}".format(ovf));
- return ovf;
- }
- function math_overflow(int8 num) public returns (int8) {
- int8 ovf = num + 120;
- print("x = {}".format(ovf));
- return ovf;
- }
- function require_test(int256 num) public returns (int8) {
- require(num > 10, "sesa");
- return 0;
- }
- // assert failure
- function assert_test(int256 num) public returns (int8) {
- assert(num > 10);
- return 0;
- }
- // storage index out of bounds
- function set_storage_bytes() public returns (bytes) {
- bytes sesa = new bytes(1);
- b[5] = sesa[0];
- return sesa;
- }
- // storage array index out of bounds
- function get_storage_bytes() public returns (bytes) {
- bytes sesa = new bytes(1);
- sesa[0] = b[5];
- return sesa;
- }
- // pop from empty storage array
- function pop_empty_storage() public {
- arr.pop();
- }
- function i_will_revert() public {
- revert();
- }
- function write_integer_failure(uint256 buf_size) public {
- bytes smol_buf = new bytes(buf_size);
- smol_buf.writeUint32LE(350, 20);
- }
- function write_bytes_failure(uint256 buf_size) public {
- bytes data = new bytes(10);
- bytes smol_buf = new bytes(buf_size);
- smol_buf.writeBytes(data, 0);
- }
- function read_integer_failure(uint32 offset) public {
- bytes smol_buf = new bytes(1);
- smol_buf.readUint16LE(offset);
- }
- // truncated type overflows
- function trunc_failure(uint256 input) public returns (uint256[]) {
- uint256[] a = new uint256[](input);
- return a;
- }
- function out_of_bounds(uint256 input) public returns (uint256) {
- uint256[] a = new uint256[](input);
- return a[20];
- }
- function invalid_instruction() public {
- assembly {
- invalid()
- }
- }
- function byte_cast_failure(uint256 num) public returns (bytes) {
- bytes smol_buf = new bytes(num);
- //bytes32 b32 = new bytes(num);
- bytes32 b32 = bytes32(smol_buf);
- return b32;
- }
- function revert_with_message() public pure {
- revert("I reverted!");
- }
- }
- @program_id("Crea1hXZv5Snuvs38GW2SJ1vJQ2Z5uBavUnwPwpiaDiQ")
- contract child {
- constructor() {}
- function say_my_name() public pure returns (string memory) {
- print("say_my_name");
- return "child";
- }
- }
- contract calle_contract {
- constructor() {}
- function calle_contract_func() public {
- revert();
- }
- }
- "#,
- );
- vm.set_program(0);
- let data_account = vm.initialize_data_account();
- vm.function("new")
- .accounts(vec![("dataAccount", data_account)])
- .call();
- let mut _res = vm
- .function("math_overflow")
- .arguments(&[BorshToken::Int {
- width: 8,
- value: BigInt::from(10u8),
- }])
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: math overflow in test.sol:22:20-29,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("require_test")
- .arguments(&[BorshToken::Int {
- width: 256,
- value: BigInt::from(9u8),
- }])
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: sesa require condition failed in test.sol:28:27-33,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("get_storage_bytes")
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: storage array index out of bounds in test.sol:48:19-23,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("set_storage_bytes")
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: storage index out of bounds in test.sol:41:11-12,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("read_integer_failure")
- .arguments(&[BorshToken::Uint {
- width: 32,
- value: BigInt::from(2u8),
- }])
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: read integer out of bounds in test.sol:74:18-30,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("trunc_failure")
- .arguments(&[BorshToken::Uint {
- width: 256,
- value: BigInt::from(u128::MAX),
- }])
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: truncated type overflows in test.sol:79:37-42,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("invalid_instruction")
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: reached invalid instruction in test.sol:90:13-22,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("pop_empty_storage")
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: pop from empty storage array in test.sol:54:9-12,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("write_bytes_failure")
- .arguments(&[BorshToken::Uint {
- width: 256,
- value: BigInt::from(9u8),
- }])
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: data does not fit into buffer in test.sol:69:18-28,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("assert_test")
- .arguments(&[BorshToken::Uint {
- width: 256,
- value: BigInt::from(9u8),
- }])
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- println!("{}", vm.logs);
- assert_eq!(
- vm.logs,
- "runtime_error: assert failure in test.sol:34:16-24,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("out_of_bounds")
- .arguments(&[BorshToken::Uint {
- width: 256,
- value: BigInt::from(19u8),
- }])
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: array index out of bounds in test.sol:85:16-21,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("write_integer_failure")
- .arguments(&[BorshToken::Uint {
- width: 256,
- value: BigInt::from(1u8),
- }])
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: integer too large to write in buffer in test.sol:63:18-31,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("byte_cast_failure")
- .arguments(&[BorshToken::Uint {
- width: 256,
- value: BigInt::from(33u8),
- }])
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: bytes cast error in test.sol:98:23-40,\n"
- );
- vm.logs.clear();
- _res = vm
- .function("i_will_revert")
- .accounts(vec![("dataAccount", data_account)])
- .must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: revert encountered in test.sol:58:9-17,\n"
- );
- vm.logs.clear();
- _res = vm.function("revert_with_message").must_fail();
- assert_eq!(
- vm.logs,
- "runtime_error: I reverted! revert encountered in test.sol:103:9-30,\n"
- );
- assert!(vm.return_data.is_none());
- }
|