simple.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::{build_solidity, BorshToken};
  3. use num_bigint::BigInt;
  4. use solang::{file_resolver::FileResolver, Target};
  5. use std::ffi::OsStr;
  6. #[test]
  7. fn simple() {
  8. let mut vm = build_solidity(
  9. r#"
  10. contract foo {
  11. constructor() {
  12. print("Hello from constructor");
  13. }
  14. function test() public {
  15. print("Hello from function");
  16. }
  17. }"#,
  18. );
  19. let data_account = vm.initialize_data_account();
  20. vm.function("new")
  21. .accounts(vec![("dataAccount", data_account)])
  22. .call();
  23. assert_eq!(vm.logs, "Hello from constructor");
  24. vm.logs.truncate(0);
  25. vm.function("test")
  26. .accounts(vec![("dataAccount", data_account)])
  27. .call();
  28. assert_eq!(vm.logs, "Hello from function");
  29. }
  30. #[test]
  31. fn format() {
  32. let mut vm = build_solidity(
  33. r#"
  34. contract foo {
  35. constructor() {
  36. int x = 21847450052839212624230656502990235142567050104912751880812823948662932355201;
  37. print("x = {}".format(x));
  38. }
  39. }"#,
  40. );
  41. let data_account = vm.initialize_data_account();
  42. vm.function("new")
  43. .accounts(vec![("dataAccount", data_account)])
  44. .call();
  45. assert_eq!(
  46. vm.logs,
  47. "x = 21847450052839212624230656502990235142567050104912751880812823948662932355201"
  48. );
  49. }
  50. #[test]
  51. fn parameters() {
  52. let mut vm = build_solidity(
  53. r#"
  54. contract foo {
  55. function test(uint32 x, uint64 y) public {
  56. if (x == 10) {
  57. print("x is 10");
  58. }
  59. if (y == 102) {
  60. print("y is 102");
  61. }
  62. }
  63. }"#,
  64. );
  65. let data_account = vm.initialize_data_account();
  66. vm.function("new")
  67. .accounts(vec![("dataAccount", data_account)])
  68. .call();
  69. vm.function("test")
  70. .arguments(&[
  71. BorshToken::Uint {
  72. width: 32,
  73. value: BigInt::from(10u8),
  74. },
  75. BorshToken::Uint {
  76. width: 64,
  77. value: BigInt::from(10u8),
  78. },
  79. ])
  80. .accounts(vec![("dataAccount", data_account)])
  81. .call();
  82. assert_eq!(vm.logs, "x is 10");
  83. vm.logs.truncate(0);
  84. vm.function("test")
  85. .arguments(&[
  86. BorshToken::Uint {
  87. width: 32,
  88. value: BigInt::from(99u8),
  89. },
  90. BorshToken::Uint {
  91. width: 64,
  92. value: BigInt::from(102u8),
  93. },
  94. ])
  95. .accounts(vec![("dataAccount", data_account)])
  96. .call();
  97. assert_eq!(vm.logs, "y is 102");
  98. }
  99. #[test]
  100. fn returns() {
  101. let mut vm = build_solidity(
  102. r#"
  103. contract foo {
  104. function test(uint32 x) public returns (uint32) {
  105. return x * x;
  106. }
  107. }"#,
  108. );
  109. let data_account = vm.initialize_data_account();
  110. vm.function("new")
  111. .accounts(vec![("dataAccount", data_account)])
  112. .call();
  113. let returns = vm
  114. .function("test")
  115. .arguments(&[BorshToken::Uint {
  116. width: 32,
  117. value: BigInt::from(10u8),
  118. }])
  119. .accounts(vec![("dataAccount", data_account)])
  120. .call()
  121. .unwrap();
  122. assert_eq!(
  123. returns,
  124. BorshToken::Uint {
  125. width: 32,
  126. value: BigInt::from(100u8)
  127. }
  128. );
  129. let mut vm = build_solidity(
  130. r#"
  131. contract foo {
  132. function test(uint64 x) public returns (bool, uint64) {
  133. return (true, x * 961748941);
  134. }
  135. }"#,
  136. );
  137. let data_account = vm.initialize_data_account();
  138. vm.function("new")
  139. .accounts(vec![("dataAccount", data_account)])
  140. .call();
  141. let returns = vm
  142. .function("test")
  143. .arguments(&[BorshToken::Uint {
  144. width: 64,
  145. value: BigInt::from(982451653u64),
  146. }])
  147. .accounts(vec![("dataAccount", data_account)])
  148. .call()
  149. .unwrap()
  150. .unwrap_tuple();
  151. assert_eq!(
  152. returns,
  153. vec![
  154. BorshToken::Bool(true),
  155. BorshToken::Uint {
  156. width: 64,
  157. value: BigInt::from(961748941u64 * 982451653u64)
  158. },
  159. ]
  160. );
  161. }
  162. #[test]
  163. fn flipper() {
  164. let mut vm = build_solidity(
  165. r#"
  166. contract flipper {
  167. bool private value;
  168. /// Constructor that initializes the `bool` value to the given `init_value`.
  169. constructor(bool initvalue) {
  170. value = initvalue;
  171. }
  172. /// A message that can be called on instantiated contracts.
  173. /// This one flips the value of the stored `bool` from `true`
  174. /// to `false` and vice versa.
  175. function flip() public {
  176. value = !value;
  177. }
  178. /// Simply returns the current value of our `bool`.
  179. function get() public view returns (bool) {
  180. return value;
  181. }
  182. }"#,
  183. );
  184. let data_account = vm.initialize_data_account();
  185. vm.function("new")
  186. .arguments(&[BorshToken::Bool(true)])
  187. .accounts(vec![("dataAccount", data_account)])
  188. .call();
  189. assert_eq!(
  190. vm.account_data[&data_account].data[0..17].to_vec(),
  191. hex::decode("6fc90ec500000000000000001800000001").unwrap()
  192. );
  193. let returns = vm
  194. .function("get")
  195. .accounts(vec![("dataAccount", data_account)])
  196. .call()
  197. .unwrap();
  198. assert_eq!(returns, BorshToken::Bool(true));
  199. vm.function("flip")
  200. .accounts(vec![("dataAccount", data_account)])
  201. .call();
  202. assert_eq!(
  203. vm.account_data[&data_account].data[0..17].to_vec(),
  204. hex::decode("6fc90ec500000000000000001800000000").unwrap()
  205. );
  206. let returns = vm
  207. .function("get")
  208. .accounts(vec![("dataAccount", data_account)])
  209. .call()
  210. .unwrap();
  211. assert_eq!(returns, BorshToken::Bool(false));
  212. }
  213. #[test]
  214. fn incrementer() {
  215. let mut vm = build_solidity(
  216. r#"
  217. contract foo {
  218. // make sure incrementer has a base contract with an empty constructor
  219. // is to check that the correct constructor is selected at emit time
  220. // https://github.com/hyperledger/solang/issues/487
  221. constructor() {}
  222. }
  223. contract incrementer is foo {
  224. uint32 private value;
  225. /// Constructor that initializes the `int32` value to the given `init_value`.
  226. constructor(uint32 initvalue) {
  227. value = initvalue;
  228. }
  229. /// This increments the value by `by`.
  230. function inc(uint32 by) public {
  231. value += by;
  232. }
  233. /// Simply returns the current value of our `uint32`.
  234. function get() public view returns (uint32) {
  235. return value;
  236. }
  237. }"#,
  238. );
  239. let data_account = vm.initialize_data_account();
  240. vm.function("new")
  241. .arguments(&[BorshToken::Uint {
  242. width: 32,
  243. value: BigInt::from(5u8),
  244. }])
  245. .accounts(vec![("dataAccount", data_account)])
  246. .call();
  247. let returns = vm
  248. .function("get")
  249. .accounts(vec![("dataAccount", data_account)])
  250. .call()
  251. .unwrap();
  252. assert_eq!(
  253. returns,
  254. BorshToken::Uint {
  255. width: 32,
  256. value: BigInt::from(5u8),
  257. }
  258. );
  259. vm.function("inc")
  260. .arguments(&[BorshToken::Uint {
  261. width: 32,
  262. value: BigInt::from(5u8),
  263. }])
  264. .accounts(vec![("dataAccount", data_account)])
  265. .call();
  266. let returns = vm
  267. .function("get")
  268. .accounts(vec![("dataAccount", data_account)])
  269. .call()
  270. .unwrap();
  271. assert_eq!(
  272. returns,
  273. BorshToken::Uint {
  274. width: 32,
  275. value: BigInt::from(10u8),
  276. }
  277. );
  278. }
  279. #[test]
  280. fn infinite_loop() {
  281. let mut cache = FileResolver::default();
  282. let src = String::from(
  283. r#"
  284. contract line {
  285. function foo() public {
  286. address x = int32(1);
  287. }
  288. }"#,
  289. );
  290. cache.set_file_contents("test.sol", src);
  291. let ns = solang::parse_and_resolve(OsStr::new("test.sol"), &mut cache, Target::Solana);
  292. ns.print_diagnostics_in_plain(&cache, false);
  293. assert_eq!(
  294. ns.diagnostics.iter().nth(1).unwrap().message,
  295. "implicit conversion from int to address not allowed"
  296. );
  297. }
  298. #[test]
  299. fn two_arrays() {
  300. let mut vm = build_solidity(
  301. r#"
  302. contract two_arrays {
  303. uint[] array1;
  304. uint[] array2;
  305. constructor() {
  306. for(uint i = 0; i < 10; i++) {
  307. unchecked {
  308. array1.push((i*uint(sha256("i"))));
  309. array2.push(((i+1)*uint(sha256("i"))));
  310. }
  311. }
  312. }
  313. }"#,
  314. );
  315. let data_account = vm.initialize_data_account();
  316. vm.function("new")
  317. .accounts(vec![("dataAccount", data_account)])
  318. .call();
  319. }
  320. #[test]
  321. fn dead_storage_bug() {
  322. let mut vm = build_solidity(
  323. r#"
  324. contract deadstorage {
  325. uint public maxlen = 10000;
  326. uint public z;
  327. uint public v;
  328. constructor() {
  329. for(uint i = 0; i < 10; i++) {
  330. uint x = i*(10e34+9999);
  331. print("x:{}".format(x));
  332. v = x%maxlen;
  333. print("v:{}".format(v));
  334. z = v%maxlen;
  335. print("z:{}".format(z));
  336. }
  337. }
  338. }"#,
  339. );
  340. let data_account = vm.initialize_data_account();
  341. vm.function("new")
  342. .accounts(vec![("dataAccount", data_account)])
  343. .call();
  344. let returns = vm
  345. .function("v")
  346. .accounts(vec![("dataAccount", data_account)])
  347. .call()
  348. .unwrap();
  349. assert_eq!(
  350. returns,
  351. BorshToken::Uint {
  352. width: 256,
  353. value: BigInt::from(9991u16)
  354. }
  355. );
  356. }
  357. #[test]
  358. fn simple_loops() {
  359. let mut runtime = build_solidity(
  360. r##"
  361. contract test3 {
  362. function foo(uint32 a) public returns (uint32) {
  363. uint32 b = 50 - a;
  364. uint32 c;
  365. c = 100 * b;
  366. c += 5;
  367. return a * 1000 + c;
  368. }
  369. function bar(uint32 b, bool x) public returns (uint32) {
  370. unchecked {
  371. uint32 i = 1;
  372. if (x) {
  373. do {
  374. i += 10;
  375. }
  376. while (b-- > 0);
  377. } else {
  378. uint32 j;
  379. for (j=2; j<10; j++) {
  380. i *= 3;
  381. }
  382. }
  383. return i;
  384. }
  385. }
  386. function baz(uint32 x) public returns (uint32) {
  387. for (uint32 i = 0; i<100; i++) {
  388. x *= 7;
  389. if (x > 200) {
  390. break;
  391. }
  392. x++;
  393. }
  394. return x;
  395. }
  396. }"##,
  397. );
  398. // call constructor
  399. let data_account = runtime.initialize_data_account();
  400. runtime
  401. .function("new")
  402. .accounts(vec![("dataAccount", data_account)])
  403. .call();
  404. for i in 0..=50 {
  405. let res = ((50 - i) * 100 + 5) + i * 1000;
  406. let returns = runtime
  407. .function("foo")
  408. .arguments(&[BorshToken::Uint {
  409. width: 32,
  410. value: BigInt::from(i),
  411. }])
  412. .accounts(vec![("dataAccount", data_account)])
  413. .call()
  414. .unwrap();
  415. assert_eq!(
  416. returns,
  417. BorshToken::Uint {
  418. width: 32,
  419. value: BigInt::from(res)
  420. }
  421. );
  422. }
  423. for i in 0..=50 {
  424. let res = (i + 1) * 10 + 1;
  425. let returns = runtime
  426. .function("bar")
  427. .arguments(&[
  428. BorshToken::Uint {
  429. width: 32,
  430. value: BigInt::from(i),
  431. },
  432. BorshToken::Bool(true),
  433. ])
  434. .accounts(vec![("dataAccount", data_account)])
  435. .call()
  436. .unwrap();
  437. assert_eq!(
  438. returns,
  439. BorshToken::Uint {
  440. width: 32,
  441. value: BigInt::from(res)
  442. }
  443. );
  444. }
  445. for i in 0..=50 {
  446. let mut res = 1;
  447. for _ in 2..10 {
  448. res *= 3;
  449. }
  450. let returns = runtime
  451. .function("bar")
  452. .arguments(&[
  453. BorshToken::Uint {
  454. width: 32,
  455. value: BigInt::from(i),
  456. },
  457. BorshToken::Bool(false),
  458. ])
  459. .accounts(vec![("dataAccount", data_account)])
  460. .call()
  461. .unwrap();
  462. assert_eq!(
  463. returns,
  464. BorshToken::Uint {
  465. width: 32,
  466. value: BigInt::from(res)
  467. }
  468. );
  469. }
  470. for i in 1..=50 {
  471. let mut res = i;
  472. for _ in 0..100 {
  473. res *= 7;
  474. if res > 200 {
  475. break;
  476. }
  477. res += 1;
  478. }
  479. let returns = runtime
  480. .function("baz")
  481. .arguments(&[BorshToken::Uint {
  482. width: 32,
  483. value: BigInt::from(i),
  484. }])
  485. .accounts(vec![("dataAccount", data_account)])
  486. .call()
  487. .unwrap();
  488. assert_eq!(
  489. returns,
  490. BorshToken::Uint {
  491. width: 32,
  492. value: BigInt::from(res)
  493. }
  494. );
  495. }
  496. }