primitives.rs 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::build_solidity_with_overflow_check;
  3. use crate::{build_solidity, BorshToken};
  4. use num_bigint::{BigInt, BigUint, RandBigInt, ToBigInt};
  5. use num_traits::{One, ToPrimitive, Zero};
  6. use rand::seq::SliceRandom;
  7. use rand::Rng;
  8. use std::ops::BitAnd;
  9. use std::ops::Div;
  10. use std::ops::Mul;
  11. use std::ops::Rem;
  12. use std::ops::Shl;
  13. use std::ops::Shr;
  14. use std::ops::Sub;
  15. use std::ops::{Add, BitOr, BitXor, MulAssign, ShlAssign, ShrAssign, SubAssign};
  16. #[test]
  17. #[should_panic]
  18. fn assert_false() {
  19. // without a working assert, this is not going to work
  20. let mut vm = build_solidity(
  21. r#"
  22. contract foo {
  23. function assert_fails() public {
  24. require(false, "humpty-dumpty");
  25. }
  26. }"#,
  27. );
  28. vm.constructor(&[]);
  29. vm.function("assert_fails", &[]);
  30. }
  31. #[test]
  32. fn assert_true() {
  33. // without a working assert, this is not going to work
  34. let mut vm = build_solidity(
  35. r#"
  36. contract foo {
  37. function assert_fails() public {
  38. require(true, "humpty-dumpty");
  39. }
  40. }"#,
  41. );
  42. vm.constructor(&[]);
  43. vm.function("assert_fails", &[]);
  44. }
  45. #[test]
  46. fn boolean() {
  47. // we need to test: literals
  48. // passing address around
  49. // abi encoding/decoding address
  50. // comparing address to another
  51. let mut vm = build_solidity(
  52. r#"
  53. contract foo {
  54. function return_true() public returns (bool) {
  55. return true;
  56. }
  57. function return_false() public returns (bool) {
  58. return false;
  59. }
  60. function true_arg(bool b) public {
  61. assert(b);
  62. }
  63. function false_arg(bool b) public {
  64. assert(!b);
  65. }
  66. }"#,
  67. );
  68. vm.constructor(&[]);
  69. let returns = vm.function("return_true", &[]).unwrap();
  70. assert_eq!(returns, BorshToken::Bool(true));
  71. let returns = vm.function("return_false", &[]).unwrap();
  72. assert_eq!(returns, BorshToken::Bool(false));
  73. vm.function("true_arg", &[BorshToken::Bool(true)]);
  74. vm.function("false_arg", &[BorshToken::Bool(false)]);
  75. }
  76. #[test]
  77. fn address() {
  78. // we need to test: literals
  79. // passing address around
  80. // abi encoding/decoding address
  81. // comparing address to another
  82. let mut vm = build_solidity(
  83. r#"
  84. contract foo {
  85. function return_address() public returns (address) {
  86. return address'CXQw5tfeRKKzV4hk6PcdyKyANSvFxoZCKwHkVXAhAYSJ';
  87. }
  88. function address_arg(address a) public {
  89. assert(a == address'66Eh1STPJgabub73TP8YbN7VNCwjaVTEJGHRxCLeBJ4A');
  90. }
  91. }"#,
  92. );
  93. vm.constructor(&[]);
  94. let returns = vm.function("return_address", &[]).unwrap();
  95. assert_eq!(
  96. returns,
  97. BorshToken::Address([
  98. 171, 59, 10, 127, 211, 122, 217, 123, 53, 213, 159, 40, 54, 36, 50, 52, 196, 144, 17,
  99. 226, 97, 168, 69, 213, 79, 14, 6, 232, 165, 44, 58, 31
  100. ]),
  101. );
  102. vm.function(
  103. "address_arg",
  104. &[BorshToken::Address([
  105. 75, 161, 209, 89, 47, 84, 50, 13, 23, 127, 94, 21, 50, 249, 250, 185, 117, 49, 186,
  106. 134, 82, 130, 112, 97, 218, 24, 157, 198, 40, 105, 118, 27,
  107. ])],
  108. );
  109. }
  110. #[test]
  111. fn test_enum() {
  112. // we need to test enum literals
  113. // abi encoding/decode literals
  114. // comparing enums
  115. let mut vm = build_solidity(
  116. r#"
  117. contract foo {
  118. enum bar { bar0, bar1, bar2, bar3, bar4, bar5, bar6, bar7, bar8, bar9, bar10 }
  119. function return_enum() public returns (bar) {
  120. return bar.bar9;
  121. }
  122. function enum_arg(bar a) public {
  123. assert(a == bar.bar6);
  124. }
  125. }"#,
  126. );
  127. vm.constructor(&[]);
  128. let returns = vm.function("return_enum", &[]).unwrap();
  129. assert_eq!(
  130. returns,
  131. BorshToken::Uint {
  132. width: 8,
  133. value: BigInt::from(9u8)
  134. }
  135. );
  136. vm.function(
  137. "enum_arg",
  138. &[BorshToken::Uint {
  139. width: 8,
  140. value: BigInt::from(6u8),
  141. }],
  142. );
  143. }
  144. #[test]
  145. fn bytes() {
  146. let mut rng = rand::thread_rng();
  147. for width in 1..32 {
  148. let src = r#"
  149. contract test {
  150. function return_literal() public returns (bytes7) {
  151. return hex"01020304050607";
  152. }
  153. function return_arg(bytes7 x) public returns (bytes7) {
  154. return x;
  155. }
  156. function or(bytesN a, bytesN b) public returns (bytesN) {
  157. return a | b;
  158. }
  159. function and(bytesN a, bytesN b) public returns (bytesN) {
  160. return a & b;
  161. }
  162. function xor(bytesN a, bytesN b) public returns (bytesN) {
  163. return a ^ b;
  164. }
  165. function shift_left(bytesN a, uint32 r) public returns (bytesN) {
  166. return a << r;
  167. }
  168. function shift_right(bytesN a, uint32 r) public returns (bytesN) {
  169. return a >> r;
  170. }
  171. }"#
  172. .replace("bytesN", &format!("bytes{width}"));
  173. let mut vm = build_solidity(&src);
  174. vm.constructor(&[]);
  175. let returns = vm.function("return_literal", &[]).unwrap();
  176. assert_eq!(
  177. returns,
  178. BorshToken::uint8_fixed_array(vec![1, 2, 3, 4, 5, 6, 7])
  179. );
  180. let returns = vm
  181. .function(
  182. "return_arg",
  183. &[BorshToken::FixedBytes(vec![1, 2, 3, 4, 5, 6, 7])],
  184. )
  185. .unwrap();
  186. assert_eq!(
  187. returns,
  188. BorshToken::uint8_fixed_array(vec![1, 2, 3, 4, 5, 6, 7])
  189. );
  190. for _ in 0..10 {
  191. let mut a = Vec::new();
  192. let mut b = Vec::new();
  193. a.resize(width, 0);
  194. b.resize(width, 0);
  195. rng.fill(&mut a[..]);
  196. rng.fill(&mut b[..]);
  197. let or = vm
  198. .function(
  199. "or",
  200. &[
  201. BorshToken::FixedBytes(a.to_vec()),
  202. BorshToken::FixedBytes(b.to_vec()),
  203. ],
  204. )
  205. .unwrap();
  206. let res: Vec<u8> = a.iter().zip(b.iter()).map(|(a, b)| a | b).collect();
  207. println!(
  208. "{} | {} = {}",
  209. hex::encode(&a),
  210. hex::encode(&b),
  211. hex::encode(&res)
  212. );
  213. assert_eq!(or, BorshToken::uint8_fixed_array(res));
  214. let and = vm
  215. .function(
  216. "and",
  217. &[
  218. BorshToken::FixedBytes(a.to_vec()),
  219. BorshToken::FixedBytes(b.to_vec()),
  220. ],
  221. )
  222. .unwrap();
  223. let res: Vec<u8> = a.iter().zip(b.iter()).map(|(a, b)| a & b).collect();
  224. assert_eq!(and, BorshToken::uint8_fixed_array(res));
  225. let xor = vm
  226. .function(
  227. "xor",
  228. &[
  229. BorshToken::FixedBytes(a.to_vec()),
  230. BorshToken::FixedBytes(b.to_vec()),
  231. ],
  232. )
  233. .unwrap();
  234. let res: Vec<u8> = a.iter().zip(b.iter()).map(|(a, b)| a ^ b).collect();
  235. assert_eq!(xor, BorshToken::uint8_fixed_array(res));
  236. let r = rng.gen::<u32>() % (width as u32 * 8);
  237. println!("w = {width} r = {r}");
  238. let shl = vm
  239. .function(
  240. "shift_left",
  241. &[
  242. BorshToken::FixedBytes(a.to_vec()),
  243. BorshToken::Uint {
  244. width: 32,
  245. value: BigInt::from(r),
  246. },
  247. ],
  248. )
  249. .unwrap();
  250. let mut res = (BigUint::from_bytes_be(&a) << r).to_bytes_be();
  251. while res.len() > width {
  252. res.remove(0);
  253. }
  254. while res.len() < width {
  255. res.insert(0, 0);
  256. }
  257. assert_eq!(shl, BorshToken::uint8_fixed_array(res));
  258. let shr = vm
  259. .function(
  260. "shift_right",
  261. &[
  262. BorshToken::FixedBytes(a.to_vec()),
  263. BorshToken::Uint {
  264. width: 32,
  265. value: BigInt::from(r),
  266. },
  267. ],
  268. )
  269. .unwrap();
  270. let mut res = (BigUint::from_bytes_be(&a) >> r).to_bytes_be();
  271. while res.len() < width {
  272. res.insert(0, 0);
  273. }
  274. assert_eq!(shr, BorshToken::uint8_fixed_array(res));
  275. }
  276. }
  277. }
  278. #[test]
  279. fn uint() {
  280. let mut rng = rand::thread_rng();
  281. for width in (8u16..=256).step_by(8) {
  282. let src = r#"
  283. contract test {
  284. function pass(uintN a) public returns (uintN) {
  285. print("x:{:x}".format(uint64(a)));
  286. return 0x7f;
  287. }
  288. function add(uintN a, uintN b) public returns (uintN) {
  289. return a + b;
  290. }
  291. function sub(uintN a, uintN b) public returns (uintN) {
  292. return a - b;
  293. }
  294. function mul(uintN a, uintN b) public returns (uintN) {
  295. unchecked {
  296. return a * b;
  297. }
  298. }
  299. function div(uintN a, uintN b) public returns (uintN) {
  300. return a / b;
  301. }
  302. function mod(uintN a, uintN b) public returns (uintN) {
  303. return a % b;
  304. }
  305. function pow(uintN a, uintN b) public returns (uintN) {
  306. unchecked {
  307. return a ** b;
  308. }
  309. }
  310. function or(uintN a, uintN b) public returns (uintN) {
  311. return a | b;
  312. }
  313. function and(uintN a, uintN b) public returns (uintN) {
  314. return a & b;
  315. }
  316. function xor(uintN a, uintN b) public returns (uintN) {
  317. return a ^ b;
  318. }
  319. function shift_left(uintN a, uint32 r) public returns (uintN) {
  320. return a << r;
  321. }
  322. function shift_right(uintN a, uint32 r) public returns (uintN) {
  323. return a >> r;
  324. }
  325. }"#
  326. .replace("uintN", &format!("uint{width}"));
  327. let mut vm = build_solidity(&src);
  328. vm.constructor(&[]);
  329. println!("width:{width}");
  330. let returned_width = width.next_power_of_two();
  331. for _ in 0..10 {
  332. let mut a = rng.gen_biguint(width as u64);
  333. let mut b = rng.gen_biguint(width as u64);
  334. if b > a {
  335. std::mem::swap(&mut a, &mut b);
  336. }
  337. let res = vm.function(
  338. "pass",
  339. &[BorshToken::Uint {
  340. width,
  341. value: a.to_bigint().unwrap(),
  342. }],
  343. );
  344. println!("{a:x} = {res:?} o");
  345. let add = vm
  346. .function(
  347. "add",
  348. &[
  349. BorshToken::Uint {
  350. width,
  351. value: a.to_bigint().unwrap(),
  352. },
  353. BorshToken::Uint {
  354. width,
  355. value: b.to_bigint().unwrap(),
  356. },
  357. ],
  358. )
  359. .unwrap();
  360. let mut res = a.clone().add(&b);
  361. truncate_biguint(&mut res, width);
  362. println!("{a:x} + {b:x} = {add:?} or {res:x}");
  363. assert_eq!(
  364. add,
  365. BorshToken::Uint {
  366. width: returned_width,
  367. value: res.to_bigint().unwrap(),
  368. }
  369. );
  370. let sub = vm
  371. .function(
  372. "sub",
  373. &[
  374. BorshToken::Uint {
  375. width,
  376. value: a.to_bigint().unwrap(),
  377. },
  378. BorshToken::Uint {
  379. width,
  380. value: b.to_bigint().unwrap(),
  381. },
  382. ],
  383. )
  384. .unwrap();
  385. let mut res = a.clone().sub(&b);
  386. truncate_biguint(&mut res, width);
  387. assert_eq!(
  388. sub,
  389. BorshToken::Uint {
  390. width: returned_width,
  391. value: res.to_bigint().unwrap(),
  392. }
  393. );
  394. let mul = vm
  395. .function(
  396. "mul",
  397. &[
  398. BorshToken::Uint {
  399. width,
  400. value: a.to_bigint().unwrap(),
  401. },
  402. BorshToken::Uint {
  403. width,
  404. value: b.to_bigint().unwrap(),
  405. },
  406. ],
  407. )
  408. .unwrap();
  409. let mut res = a.clone().mul(&b);
  410. truncate_biguint(&mut res, width);
  411. assert_eq!(
  412. mul,
  413. BorshToken::Uint {
  414. width: returned_width,
  415. value: res.to_bigint().unwrap(),
  416. }
  417. );
  418. if let Some(mut n) = b.to_u32() {
  419. n %= 65536;
  420. let pow = vm
  421. .function(
  422. "pow",
  423. &[
  424. BorshToken::Uint {
  425. width,
  426. value: a.to_bigint().unwrap(),
  427. },
  428. BorshToken::Uint {
  429. width,
  430. value: BigInt::from(n),
  431. },
  432. ],
  433. )
  434. .unwrap();
  435. let mut res = a.clone().pow(n);
  436. truncate_biguint(&mut res, width);
  437. assert_eq!(
  438. pow,
  439. BorshToken::Uint {
  440. width: returned_width,
  441. value: res.to_bigint().unwrap(),
  442. }
  443. );
  444. }
  445. if b != BigUint::zero() {
  446. let div = vm
  447. .function(
  448. "div",
  449. &[
  450. BorshToken::Uint {
  451. width,
  452. value: a.to_bigint().unwrap(),
  453. },
  454. BorshToken::Uint {
  455. width,
  456. value: b.to_bigint().unwrap(),
  457. },
  458. ],
  459. )
  460. .unwrap();
  461. let mut res = a.clone().div(&b);
  462. truncate_biguint(&mut res, width);
  463. assert_eq!(
  464. div,
  465. BorshToken::Uint {
  466. width: returned_width,
  467. value: res.to_bigint().unwrap(),
  468. }
  469. );
  470. let add = vm
  471. .function(
  472. "mod",
  473. &[
  474. BorshToken::Uint {
  475. width,
  476. value: a.to_bigint().unwrap(),
  477. },
  478. BorshToken::Uint {
  479. width,
  480. value: b.to_bigint().unwrap(),
  481. },
  482. ],
  483. )
  484. .unwrap();
  485. let mut res = a.clone().rem(&b);
  486. truncate_biguint(&mut res, width);
  487. assert_eq!(
  488. add,
  489. BorshToken::Uint {
  490. width: returned_width,
  491. value: res.to_bigint().unwrap(),
  492. }
  493. );
  494. }
  495. let or = vm
  496. .function(
  497. "or",
  498. &[
  499. BorshToken::Uint {
  500. width,
  501. value: a.to_bigint().unwrap(),
  502. },
  503. BorshToken::Uint {
  504. width,
  505. value: b.to_bigint().unwrap(),
  506. },
  507. ],
  508. )
  509. .unwrap();
  510. let mut res = a.clone().bitor(&b);
  511. truncate_biguint(&mut res, width);
  512. assert_eq!(
  513. or,
  514. BorshToken::Uint {
  515. width: returned_width,
  516. value: res.to_bigint().unwrap(),
  517. }
  518. );
  519. let and = vm
  520. .function(
  521. "and",
  522. &[
  523. BorshToken::Uint {
  524. width,
  525. value: a.to_bigint().unwrap(),
  526. },
  527. BorshToken::Uint {
  528. width,
  529. value: b.to_bigint().unwrap(),
  530. },
  531. ],
  532. )
  533. .unwrap();
  534. let mut res = a.clone().bitand(&b);
  535. truncate_biguint(&mut res, width);
  536. assert_eq!(
  537. and,
  538. BorshToken::Uint {
  539. width: returned_width,
  540. value: res.to_bigint().unwrap(),
  541. }
  542. );
  543. let xor = vm
  544. .function(
  545. "xor",
  546. &[
  547. BorshToken::Uint {
  548. width,
  549. value: a.to_bigint().unwrap(),
  550. },
  551. BorshToken::Uint {
  552. width,
  553. value: b.to_bigint().unwrap(),
  554. },
  555. ],
  556. )
  557. .unwrap();
  558. let mut res = a.clone().bitxor(&b);
  559. truncate_biguint(&mut res, width);
  560. assert_eq!(
  561. xor,
  562. BorshToken::Uint {
  563. width: returned_width,
  564. value: res.to_bigint().unwrap(),
  565. }
  566. );
  567. let r = rng.gen::<u32>() % (width as u32);
  568. let shl = vm
  569. .function(
  570. "shift_left",
  571. &[
  572. BorshToken::Uint {
  573. width,
  574. value: a.to_bigint().unwrap(),
  575. },
  576. BorshToken::Uint {
  577. width: 32,
  578. value: BigInt::from(r),
  579. },
  580. ],
  581. )
  582. .unwrap();
  583. let mut res = a.clone();
  584. res.shl_assign(r);
  585. truncate_biguint(&mut res, width);
  586. assert_eq!(
  587. shl,
  588. BorshToken::Uint {
  589. width: returned_width,
  590. value: res.to_bigint().unwrap(),
  591. }
  592. );
  593. let shr = vm
  594. .function(
  595. "shift_right",
  596. &[
  597. BorshToken::Uint {
  598. width,
  599. value: a.to_bigint().unwrap(),
  600. },
  601. BorshToken::Uint {
  602. width: 32,
  603. value: BigInt::from(r),
  604. },
  605. ],
  606. )
  607. .unwrap();
  608. let mut res = a.clone();
  609. res.shr_assign(&r);
  610. truncate_biguint(&mut res, width);
  611. assert_eq!(
  612. shr,
  613. BorshToken::Uint {
  614. width: returned_width,
  615. value: res.to_bigint().unwrap(),
  616. }
  617. );
  618. }
  619. }
  620. }
  621. fn truncate_biguint(n: &mut BigUint, width: u16) {
  622. let mut bytes = n.to_bytes_le();
  623. let byte_width = (width / 8) as usize;
  624. if bytes.len() < byte_width {
  625. return;
  626. }
  627. for item in bytes.iter_mut().skip(byte_width) {
  628. *item = 0;
  629. }
  630. *n = BigUint::from_bytes_le(&bytes);
  631. }
  632. #[test]
  633. fn test_power_overflow_boundaries() {
  634. for width in (8u16..=256).step_by(8) {
  635. let src = r#"
  636. contract test {
  637. function pow(uintN a, uintN b) public returns (uintN) {
  638. return a ** b;
  639. }
  640. }"#
  641. .replace("intN", &format!("int{width}"));
  642. let mut contract = build_solidity_with_overflow_check(&src, true);
  643. contract.constructor(&[]);
  644. let return_value = contract
  645. .function(
  646. "pow",
  647. &[
  648. BorshToken::Uint {
  649. width,
  650. value: BigInt::from(2u8),
  651. },
  652. BorshToken::Uint {
  653. width,
  654. value: BigInt::from(width - 1),
  655. },
  656. ],
  657. )
  658. .unwrap();
  659. let res = BigUint::from(2_u32).pow((width - 1) as u32);
  660. assert_eq!(
  661. return_value,
  662. BorshToken::Uint {
  663. width: width.next_power_of_two(),
  664. value: res.to_bigint().unwrap(),
  665. }
  666. );
  667. let sesa = contract.function_must_fail(
  668. "pow",
  669. &[
  670. BorshToken::Uint {
  671. width,
  672. value: BigInt::from(2u8),
  673. },
  674. BorshToken::Uint {
  675. width,
  676. value: BigInt::from(width + 1),
  677. },
  678. ],
  679. );
  680. assert_ne!(sesa, Ok(0));
  681. }
  682. }
  683. #[test]
  684. fn test_overflow_boundaries() {
  685. for width in (8..=256).step_by(8) {
  686. let src = r#"
  687. contract test {
  688. function mul(intN a, intN b) public returns (intN) {
  689. return a * b;
  690. }
  691. }"#
  692. .replace("intN", &format!("int{width}"));
  693. let mut contract = build_solidity_with_overflow_check(&src, true);
  694. // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1]. We generate these boundaries:
  695. let mut upper_boundary: BigInt = BigInt::from(2_u32).pow((width - 1) as u32);
  696. upper_boundary.sub_assign(1);
  697. let mut lower_boundary: BigInt = BigInt::from(2_u32).pow((width - 1) as u32);
  698. lower_boundary.mul_assign(-1);
  699. let second_op = BigInt::from(1_u32);
  700. let returned_width = (width as u16).next_power_of_two();
  701. // Multiply the boundaries by 1.
  702. contract.constructor(&[]);
  703. let return_value = contract
  704. .function(
  705. "mul",
  706. &[
  707. BorshToken::Int {
  708. width: width as u16,
  709. value: upper_boundary.clone(),
  710. },
  711. BorshToken::Int {
  712. width: width as u16,
  713. value: second_op.clone(),
  714. },
  715. ],
  716. )
  717. .unwrap();
  718. assert_eq!(
  719. return_value,
  720. BorshToken::Int {
  721. width: returned_width,
  722. value: upper_boundary.clone(),
  723. }
  724. );
  725. let return_value = contract
  726. .function(
  727. "mul",
  728. &[
  729. BorshToken::Int {
  730. width: width as u16,
  731. value: lower_boundary.clone(),
  732. },
  733. BorshToken::Int {
  734. width: width as u16,
  735. value: second_op.clone(),
  736. },
  737. ],
  738. )
  739. .unwrap();
  740. assert_eq!(
  741. return_value,
  742. BorshToken::Int {
  743. width: returned_width,
  744. value: lower_boundary.clone(),
  745. },
  746. );
  747. let upper_boundary_plus_one: BigInt = BigInt::from(2_u32).pow((width - 1) as u32);
  748. // We subtract 2 instead of one to make the number even, so that no rounding occurs when we divide by 2 later on.
  749. let mut lower_boundary_minus_two: BigInt = BigInt::from(2_u32).pow((width - 1) as u32);
  750. lower_boundary_minus_two.mul_assign(-1_i32);
  751. lower_boundary_minus_two.sub_assign(2_i32);
  752. let upper_second_op = upper_boundary_plus_one.div(2);
  753. let lower_second_op = lower_boundary_minus_two.div(2);
  754. let res = contract.function_must_fail(
  755. "mul",
  756. &[
  757. BorshToken::Int {
  758. width: width as u16,
  759. value: upper_second_op,
  760. },
  761. BorshToken::Int {
  762. width: width as u16,
  763. value: BigInt::from(2u8),
  764. },
  765. ],
  766. );
  767. assert_ne!(res, Ok(0));
  768. let res = contract.function_must_fail(
  769. "mul",
  770. &[
  771. BorshToken::Int {
  772. width: width as u16,
  773. value: lower_second_op,
  774. },
  775. BorshToken::Int {
  776. width: width as u16,
  777. value: BigInt::from(2),
  778. },
  779. ],
  780. );
  781. assert_ne!(res, Ok(0));
  782. let res = contract.function_must_fail(
  783. "mul",
  784. &[
  785. BorshToken::Int {
  786. width: width as u16,
  787. value: upper_boundary.clone(),
  788. },
  789. BorshToken::Int {
  790. width: width as u16,
  791. value: upper_boundary.clone(),
  792. },
  793. ],
  794. );
  795. assert_ne!(res, Ok(0));
  796. let res = contract.function_must_fail(
  797. "mul",
  798. &[
  799. BorshToken::Int {
  800. width: width as u16,
  801. value: lower_boundary.clone(),
  802. },
  803. BorshToken::Int {
  804. width: width as u16,
  805. value: lower_boundary.clone(),
  806. },
  807. ],
  808. );
  809. assert_ne!(res, Ok(0));
  810. let res = contract.function_must_fail(
  811. "mul",
  812. &[
  813. BorshToken::Int {
  814. width: width as u16,
  815. value: upper_boundary.clone(),
  816. },
  817. BorshToken::Int {
  818. width: width as u16,
  819. value: lower_boundary.clone(),
  820. },
  821. ],
  822. );
  823. assert_ne!(res, Ok(0));
  824. }
  825. }
  826. #[test]
  827. fn test_mul_within_range_signed() {
  828. let mut rng = rand::thread_rng();
  829. for width in (8..=256).step_by(8) {
  830. let src = r#"
  831. contract test {
  832. function mul(intN a, intN b) public returns (intN) {
  833. print("{}*{}".format(a, b));
  834. return a * b;
  835. }
  836. }"#
  837. .replace("intN", &format!("int{width}"));
  838. let mut contract = build_solidity(&src);
  839. // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1]. Here we generate a random number within this range and multiply it by -1, 1 or 0.
  840. let first_operand_rand = rng.gen_bigint(width - 1).sub(1_u32);
  841. println!("First op : {first_operand_rand:?}");
  842. let side = vec![-1, 0, 1];
  843. // -1, 1 or 0
  844. let second_op = BigInt::from(*side.choose(&mut rng).unwrap());
  845. println!("second op : {second_op:?}");
  846. contract.constructor(&[]);
  847. let return_value = contract
  848. .function(
  849. "mul",
  850. &[
  851. BorshToken::Int {
  852. width: width as u16,
  853. value: first_operand_rand.clone(),
  854. },
  855. BorshToken::Int {
  856. width: width as u16,
  857. value: second_op.clone(),
  858. },
  859. ],
  860. )
  861. .unwrap();
  862. let res = first_operand_rand.mul(second_op);
  863. assert_eq!(
  864. return_value,
  865. BorshToken::Int {
  866. width: width.next_power_of_two() as u16,
  867. value: res,
  868. }
  869. );
  870. }
  871. }
  872. #[test]
  873. fn test_mul_within_range() {
  874. let mut rng = rand::thread_rng();
  875. for width in (8..=256).step_by(8) {
  876. let src = r#"
  877. contract test {
  878. function mul(uintN a, uintN b) public returns (uintN) {
  879. return a * b;
  880. }
  881. }"#
  882. .replace("intN", &format!("int{width}"));
  883. let mut contract = build_solidity_with_overflow_check(&src, true);
  884. contract.constructor(&[]);
  885. for _ in 0..10 {
  886. // Max number to fit unsigned N bits is (2^N)-1
  887. let mut limit: BigUint = BigUint::from(2_u32).pow(width as u32);
  888. limit.sub_assign(1u8);
  889. // Generate a random number within the the range [0, 2^N -1]
  890. let first_operand_rand = rng.gen_biguint_range(&BigUint::from(1usize), &limit);
  891. // Calculate a number that when multiplied by first_operand_rand, the result will not overflow N bits (the result of this division will cast the float result to int result, therefore lowering it. The result of multiplication will never overflow).
  892. let second_operand_rand = limit.div(&first_operand_rand);
  893. let return_value = contract
  894. .function(
  895. "mul",
  896. &[
  897. BorshToken::Uint {
  898. width: width as u16,
  899. value: first_operand_rand.to_bigint().unwrap(),
  900. },
  901. BorshToken::Uint {
  902. width: width as u16,
  903. value: second_operand_rand.to_bigint().unwrap(),
  904. },
  905. ],
  906. )
  907. .unwrap();
  908. let res = first_operand_rand * second_operand_rand;
  909. assert_eq!(
  910. return_value,
  911. BorshToken::Uint {
  912. width: (width as u16).next_power_of_two(),
  913. value: res.to_bigint().unwrap(),
  914. }
  915. );
  916. }
  917. }
  918. }
  919. #[test]
  920. fn test_overflow_detect_signed() {
  921. let mut rng = rand::thread_rng();
  922. for width in (8..=256).step_by(8) {
  923. let src = r#"
  924. contract test {
  925. function mul(intN a, intN b) public returns (intN) {
  926. return a * b;
  927. }
  928. }"#
  929. .replace("intN", &format!("int{width}"));
  930. let mut contract = build_solidity_with_overflow_check(&src, true);
  931. contract.constructor(&[]);
  932. // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1] .
  933. let mut limit: BigInt = BigInt::from(2_u32).pow((width - 1) as u32);
  934. limit.sub_assign(1u8);
  935. // Generate a random number within the the range [(2^N-1)/2, (2^N-1) -1]
  936. let first_operand_rand =
  937. rng.gen_bigint_range(&(limit.clone().div(2usize)).add(1usize), &limit);
  938. // Calculate a number that when multiplied by first_operand_rand, the result will overflow N bits
  939. let second_operand_rand = rng.gen_bigint_range(&BigInt::from(2usize), &limit);
  940. let res = contract.function_must_fail(
  941. "mul",
  942. &[
  943. BorshToken::Int {
  944. width: width as u16,
  945. value: first_operand_rand.clone(),
  946. },
  947. BorshToken::Int {
  948. width: width as u16,
  949. value: second_operand_rand.clone(),
  950. },
  951. ],
  952. );
  953. assert_ne!(res, Ok(0));
  954. // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1] .
  955. let mut lower_limit: BigInt = BigInt::from(2_u32).pow((width - 1) as u32);
  956. lower_limit.sub_assign(1usize);
  957. lower_limit.mul_assign(-1_i32);
  958. // Generate a random number within the the range [-(2^N-1), -(2^N-1)/2]
  959. let first_operand_rand =
  960. rng.gen_bigint_range(&lower_limit, &(lower_limit.clone().div(2usize)).add(1usize));
  961. let res = contract.function_must_fail(
  962. "mul",
  963. &[
  964. BorshToken::Int {
  965. width: width as u16,
  966. value: first_operand_rand.clone(),
  967. },
  968. BorshToken::Int {
  969. width: width as u16,
  970. value: second_operand_rand.clone(),
  971. },
  972. ],
  973. );
  974. assert_ne!(res, Ok(0));
  975. }
  976. }
  977. #[test]
  978. fn test_overflow_detect_unsigned() {
  979. let mut rng = rand::thread_rng();
  980. for width in (8..=256).step_by(8) {
  981. let src = r#"
  982. contract test {
  983. function mul(uintN a, uintN b) public returns (uintN) {
  984. return a * b;
  985. }
  986. }"#
  987. .replace("intN", &format!("int{width}"));
  988. let mut contract = build_solidity_with_overflow_check(&src, true);
  989. contract.constructor(&[]);
  990. for _ in 0..10 {
  991. // N bits can hold the range [0, (2^N)-1]. Generate a value that overflows N bits
  992. let mut limit: BigUint = BigUint::from(2_u32).pow(width as u32);
  993. limit.sub_assign(1u8);
  994. // Generate a random number within the the range [(2^N-1)/2, 2^N -1]
  995. let first_operand_rand =
  996. rng.gen_biguint_range(&(limit.clone().div(2usize)).add(1usize), &limit);
  997. // Calculate a number that when multiplied by first_operand_rand, the result will overflow N bits
  998. let second_operand_rand = rng.gen_biguint_range(&BigUint::from(2usize), &limit);
  999. let res = contract.function_must_fail(
  1000. "mul",
  1001. &[
  1002. BorshToken::Uint {
  1003. width: width as u16,
  1004. value: first_operand_rand.to_bigint().unwrap(),
  1005. },
  1006. BorshToken::Uint {
  1007. width: width as u16,
  1008. value: second_operand_rand.to_bigint().unwrap(),
  1009. },
  1010. ],
  1011. );
  1012. assert_ne!(res, Ok(0));
  1013. }
  1014. }
  1015. }
  1016. #[test]
  1017. fn int() {
  1018. let mut rng = rand::thread_rng();
  1019. for width in (8..=256).step_by(8) {
  1020. let src = r#"
  1021. contract test {
  1022. function add(intN a, intN b) public returns (intN) {
  1023. return a + b;
  1024. }
  1025. function sub(intN a, intN b) public returns (intN) {
  1026. return a - b;
  1027. }
  1028. function mul(intN a, intN b) public returns (intN) {
  1029. unchecked {
  1030. return a * b;
  1031. }
  1032. }
  1033. function div(intN a, intN b) public returns (intN) {
  1034. return a / b;
  1035. }
  1036. function mod(intN a, intN b) public returns (intN) {
  1037. return a % b;
  1038. }
  1039. function or(intN a, intN b) public returns (intN) {
  1040. return a | b;
  1041. }
  1042. function and(intN a, intN b) public returns (intN) {
  1043. return a & b;
  1044. }
  1045. function xor(intN a, intN b) public returns (intN) {
  1046. return a ^ b;
  1047. }
  1048. function shift_left(intN a, uint32 r) public returns (intN) {
  1049. return a << r;
  1050. }
  1051. function shift_right(intN a, uint32 r) public returns (intN) {
  1052. return a >> r;
  1053. }
  1054. }"#
  1055. .replace("intN", &format!("int{width}"));
  1056. let mut vm = build_solidity(&src);
  1057. vm.constructor(&[]);
  1058. let returned_width = (width as u16).next_power_of_two();
  1059. for _ in 0..10 {
  1060. let a = rng.gen_bigint(width - 1);
  1061. let b = rng.gen_bigint(width - 1);
  1062. let add = vm
  1063. .function(
  1064. "add",
  1065. &[
  1066. BorshToken::Int {
  1067. width: width as u16,
  1068. value: a.clone(),
  1069. },
  1070. BorshToken::Int {
  1071. width: width as u16,
  1072. value: b.clone(),
  1073. },
  1074. ],
  1075. )
  1076. .unwrap();
  1077. let mut res = a.clone().add(&b);
  1078. truncate_bigint(&mut res, width as usize);
  1079. assert_eq!(
  1080. add,
  1081. BorshToken::Int {
  1082. width: returned_width,
  1083. value: res,
  1084. }
  1085. );
  1086. let sub = vm
  1087. .function(
  1088. "sub",
  1089. &[
  1090. BorshToken::Int {
  1091. width: width as u16,
  1092. value: a.clone(),
  1093. },
  1094. BorshToken::Int {
  1095. width: width as u16,
  1096. value: b.clone(),
  1097. },
  1098. ],
  1099. )
  1100. .unwrap();
  1101. let mut res = a.clone().sub(&b);
  1102. truncate_bigint(&mut res, width as usize);
  1103. assert_eq!(
  1104. sub,
  1105. BorshToken::Int {
  1106. width: returned_width,
  1107. value: res,
  1108. }
  1109. );
  1110. let mul = vm
  1111. .function(
  1112. "mul",
  1113. &[
  1114. BorshToken::Int {
  1115. width: width as u16,
  1116. value: a.clone(),
  1117. },
  1118. BorshToken::Int {
  1119. width: width as u16,
  1120. value: b.clone(),
  1121. },
  1122. ],
  1123. )
  1124. .unwrap();
  1125. let mut res = a.clone().mul(&b);
  1126. truncate_bigint(&mut res, width as usize);
  1127. assert_eq!(
  1128. mul,
  1129. BorshToken::Int {
  1130. width: returned_width,
  1131. value: res,
  1132. }
  1133. );
  1134. if b != BigInt::zero() {
  1135. let div = vm
  1136. .function(
  1137. "div",
  1138. &[
  1139. BorshToken::Int {
  1140. width: width as u16,
  1141. value: a.clone(),
  1142. },
  1143. BorshToken::Int {
  1144. width: width as u16,
  1145. value: b.clone(),
  1146. },
  1147. ],
  1148. )
  1149. .unwrap();
  1150. let mut res = a.clone().div(&b);
  1151. truncate_bigint(&mut res, width as usize);
  1152. assert_eq!(
  1153. div,
  1154. BorshToken::Int {
  1155. width: returned_width,
  1156. value: res,
  1157. }
  1158. );
  1159. let add = vm
  1160. .function(
  1161. "mod",
  1162. &[
  1163. BorshToken::Int {
  1164. width: width as u16,
  1165. value: a.clone(),
  1166. },
  1167. BorshToken::Int {
  1168. width: width as u16,
  1169. value: b.clone(),
  1170. },
  1171. ],
  1172. )
  1173. .unwrap();
  1174. let mut res = a.clone().rem(&b);
  1175. truncate_bigint(&mut res, width as usize);
  1176. assert_eq!(
  1177. add,
  1178. BorshToken::Int {
  1179. width: returned_width,
  1180. value: res,
  1181. }
  1182. );
  1183. }
  1184. let or = vm
  1185. .function(
  1186. "or",
  1187. &[
  1188. BorshToken::Int {
  1189. width: width as u16,
  1190. value: a.clone(),
  1191. },
  1192. BorshToken::Int {
  1193. width: width as u16,
  1194. value: b.clone(),
  1195. },
  1196. ],
  1197. )
  1198. .unwrap();
  1199. let mut res = a.clone().bitor(&b);
  1200. truncate_bigint(&mut res, width as usize);
  1201. assert_eq!(
  1202. or,
  1203. BorshToken::Int {
  1204. width: returned_width,
  1205. value: res,
  1206. }
  1207. );
  1208. let and = vm
  1209. .function(
  1210. "and",
  1211. &[
  1212. BorshToken::Int {
  1213. width: width as u16,
  1214. value: a.clone(),
  1215. },
  1216. BorshToken::Int {
  1217. width: width as u16,
  1218. value: b.clone(),
  1219. },
  1220. ],
  1221. )
  1222. .unwrap();
  1223. let mut res = a.clone().bitand(&b);
  1224. truncate_bigint(&mut res, width as usize);
  1225. assert_eq!(
  1226. and,
  1227. BorshToken::Int {
  1228. width: returned_width,
  1229. value: res,
  1230. }
  1231. );
  1232. let xor = vm
  1233. .function(
  1234. "xor",
  1235. &[
  1236. BorshToken::Int {
  1237. width: width as u16,
  1238. value: a.clone(),
  1239. },
  1240. BorshToken::Int {
  1241. width: width as u16,
  1242. value: b.clone(),
  1243. },
  1244. ],
  1245. )
  1246. .unwrap();
  1247. let mut res = a.clone().bitxor(&b);
  1248. truncate_bigint(&mut res, width as usize);
  1249. assert_eq!(
  1250. xor,
  1251. BorshToken::Int {
  1252. width: returned_width,
  1253. value: res,
  1254. }
  1255. );
  1256. let r = rng.gen::<u32>() % (width as u32);
  1257. let shl = vm
  1258. .function(
  1259. "shift_left",
  1260. &[
  1261. BorshToken::Int {
  1262. width: width as u16,
  1263. value: a.clone(),
  1264. },
  1265. BorshToken::Uint {
  1266. width: 32,
  1267. value: BigInt::from(r),
  1268. },
  1269. ],
  1270. )
  1271. .unwrap();
  1272. let mut res = a.clone().shl(r);
  1273. truncate_bigint(&mut res, width as usize);
  1274. assert_eq!(
  1275. shl,
  1276. BorshToken::Int {
  1277. width: returned_width,
  1278. value: res,
  1279. }
  1280. );
  1281. let shr = vm
  1282. .function(
  1283. "shift_right",
  1284. &[
  1285. BorshToken::Int {
  1286. width: width as u16,
  1287. value: a.clone(),
  1288. },
  1289. BorshToken::Uint {
  1290. width: 32,
  1291. value: BigInt::from(r),
  1292. },
  1293. ],
  1294. )
  1295. .unwrap();
  1296. let mut res = a.shr(r);
  1297. truncate_bigint(&mut res, width as usize);
  1298. assert_eq!(
  1299. shr,
  1300. BorshToken::Int {
  1301. width: returned_width,
  1302. value: res,
  1303. }
  1304. );
  1305. }
  1306. }
  1307. }
  1308. fn truncate_bigint(n: &mut BigInt, width: usize) {
  1309. let mut bytes_le = n.to_signed_bytes_le();
  1310. let bytes_width = width / 8;
  1311. if bytes_le.len() < bytes_width {
  1312. return;
  1313. }
  1314. while bytes_le.len() > bytes_width {
  1315. bytes_le.pop();
  1316. }
  1317. *n = BigInt::from_signed_bytes_le(&bytes_le);
  1318. }
  1319. #[test]
  1320. fn bytes_cast() {
  1321. let mut vm = build_solidity(
  1322. r#"
  1323. contract foo {
  1324. function to_bytes(bytes4 b) public returns (bytes) {
  1325. return b;
  1326. }
  1327. function to_bytes5(bytes b) public returns (bytes5) {
  1328. return b;
  1329. }
  1330. }
  1331. "#,
  1332. );
  1333. vm.constructor(&[]);
  1334. let returns = vm
  1335. .function("to_bytes", &[BorshToken::FixedBytes(b"abcd".to_vec())])
  1336. .unwrap();
  1337. assert_eq!(returns, BorshToken::Bytes(b"abcd".to_vec()));
  1338. let returns = vm
  1339. .function("to_bytes5", &[BorshToken::Bytes(b"abcde".to_vec())])
  1340. .unwrap();
  1341. assert_eq!(returns, BorshToken::uint8_fixed_array(b"abcde".to_vec()));
  1342. }
  1343. #[test]
  1344. fn shift_after_load() {
  1345. let mut vm = build_solidity(
  1346. r#"
  1347. contract OneSwapToken {
  1348. function testIt(uint256[] calldata mixedAddrVal) public pure returns (uint256, uint256) {
  1349. uint256 a = mixedAddrVal[0]<<2;
  1350. uint256 b = mixedAddrVal[1]>>2;
  1351. return (a, b);
  1352. }
  1353. }
  1354. "#,
  1355. );
  1356. vm.constructor(&[]);
  1357. let args = BorshToken::Array(vec![
  1358. BorshToken::Uint {
  1359. width: 256,
  1360. value: BigInt::one(),
  1361. },
  1362. BorshToken::Uint {
  1363. width: 256,
  1364. value: BigInt::from(4u8),
  1365. },
  1366. ]);
  1367. let returns = vm.function("testIt", &[args]).unwrap().unwrap_tuple();
  1368. assert_eq!(returns.len(), 2);
  1369. assert_eq!(
  1370. returns[0],
  1371. BorshToken::Uint {
  1372. width: 256,
  1373. value: BigInt::from(4u8)
  1374. }
  1375. );
  1376. assert_eq!(
  1377. returns[1],
  1378. BorshToken::Uint {
  1379. width: 256,
  1380. value: BigInt::one(),
  1381. }
  1382. );
  1383. }